推导式及生成器

 

1、推导式 (comprehensions)

# 语法 ---> var for var in iterable

  

1.1 列表推导式

# res = [var for var in iterable ]
​
# 基本语法
print([i for i in range(100)])
​
# 单循环 + 判断
print([i for i in range(100) if i % 2 == 1])
​
# 双循环 + 判断
lst1 = ["中国","美国","牙买加"]
lst2 = ["黄种人","白种人","黑种人"]
​
print([i + ":" + j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)])

  

1.1.1 列表推导式练习题

(1).{'x': 'A', 'y': 'B', 'z': 'C' } 把字典写成x=A,y=B,z=C的列表推导式
dic = {'x': 'A', 'y': 'B', 'z': 'C' }
print([ k + "=" + v for k,v in dic.items()])
​
(2).把列表中所有字符变成小写  ["ADDD","dddDD","DDaa","sss"]
lst = ["ADDD","dddDD","DDaa","sss"]
print([i.lower() for i in lst])
​
(3).x是0-5之间的偶数,y是0-5之间的奇数 把x,y组成一起变成元组,放到列表当中
print([(x,y) for x in range(0,5,2) for y in range(1,6,2)])
​
(4).使用列表推导式 制作所有99乘法表中的运算
print(["{}*{}={:2d}".format(i,j,i*j) for i in range(1,9) for j in range(1,i+1)])
​
(5)#求M,N中矩阵和元素的乘积
M = [ [1,2,3],[4,5,6],[7,8,9]]
N = [ [2,2,2],[3,3,3],[4,4,4]]
=>实现效果1   [2, 4, 6, 12, 15, 18, 28, 32, 36]
=>实现效果2   [[2, 4, 6], [12, 15, 18], [28, 32, 36]]j
​
res1 = [M[i][j]*N[i][j] for i in range(3) for j in range(3)]
res2 = [[M[i][j]*N[i][j] for j in range(3) ] for i in range(3)]

 

1.2 集合推导式

# res = {var for var in iterable}  ---> 去重,无序 (一般用于统计种类)
​
"""
案例:
    满足年龄在18到21,存款大于等于5000 小于等于5500的人,
    开卡格式为:尊贵VIP卡老x(姓氏),否则开卡格式为:抠脚大汉卡老x(姓氏)  
    把开卡的种类统计出来
"""
​
listvar = [
    {"name":"赵一","age":18,"money":9000},
    {"name":"钱二","age":19,"money":5100},
    {"name":"孙三","age":20,"money":4800},
    {"name":"李四","age":21,"money":2000},
    {"name":"周五","age":18,"money":1480}   ]
​
# 常规写法
setvar = set()
for i in listvar:
    if 18 <= i["age"] <= 21 and  5000 <= i["money"] <= 5500:
        res = "尊贵VIP卡老" + i["name"][0]
    else:
        res = "抠脚大汉卡老" + i["name"][0]
    setvar.add(res)
print(setvar)
​
# 改写成集合推导式 ---> {三元运算符 + 推导式}
setvar = { "尊贵VIP卡老" + i["name"][0] if 18 <= i["age"] <= 21 and  5000 <= i["money"] <= 5500 else "抠脚大汉卡老" + i["name"][0] for i in listvar }
print(setvar)

  

1.3 字典推导式

# {k,v for k,v in iterable}
# iterable 必须是等长二级容器,且个数为二

  

1.3.1 enumerate ,zip

# enumerate (iterable,start=0)
"""
功能:枚举 ---> 将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中
参数:
    iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) 
    start:  可以选择开始的索引号(默认从0开始索引)
返回值:迭代器
"""
lst = ["赵","钱","孙","李","周","吴","郑","王"]
res = enumerate(lst,start=1)   # [(1, '赵'),(2, '钱'),(3, '孙'),(4, '李'),(5, '周'),(6, '吴'),(7, '郑'),(8, '王')]
print(list(res))    
​
# zip (iterable1, iterable2,...)
"""
功能: 将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中
    iterable: 可迭代性数据 (常用:迭代器,容器类型数据,可迭代对象range) 
返回: 迭代器
特征: 如果找不到对应配对的元素,当前元素会被舍弃
"""
lst1 = [1,2,3,4,5]
lst2 = ["赵","钱","孙","李","周","吴","郑","王"]
print(list(zip(lst1,lst2)))    # [(1, '赵'), (2, '钱'), (3, '孙'), (4, '李'), (5, '周')]

  

1.3.2 字典推导式

lst1 = [1,2,3,4,5]
lst2 = ["赵","钱","孙","李","周","吴","郑","王"]
​
# 利用 enumerate 形成字典
res = { k:v for k,v in enumerate(lst2,start=1)}
​
# 利用 zip 形成字典
res = { k:v for k,v in zip(lst1,lst2)}
​
# dict 强转字典
res = dict(enumerate(lst2,start=1))
res = dict(zip(lst1,lst2))

  

2、生成器 (generator)

# 生成器本质是迭代器,允许自定义逻辑的迭代器
# 迭代器和生成器区别:迭代器本身是系统内置的.重写不了.而生成器是用户自定义的,可以重写迭代逻辑
# 生成器可以用两种方式创建:
    (1)生成器表达式  (里面是推导式,外面用圆括号)
    (2)生成器函数    (用def定义,里面含有yield)
    
    yield 与 return
    共同点于:执行到这句话都会把值返回出去
    不同点: yield 每次返回时,会记住上次离开时执行的位置 , 下次在调用生成器 , 会从上次执行的位置往下走,
            而return直接终止函数,每次重头调用. yield 6 和 yield(6) 2种写法都可以 yield 6 更像 return 6 的写法 推荐使用

  

2.1 生成器函数

# 定义
def func()
    print("执行生成器")
    yield 1
    
# 初始化生成器函数,返回生成器对象,简称生成器
gen_func = func()
​
# 调用生成器
res = next(gen_func)         # 执行生成器
print(res)                   # 打印 yield 返回值

  

2.1.1 生成器函数的应用示例

def func():
    for i in range(1,101):
        yield "该球衣号码是{}".format(i)
​
# 初始化生成器函数  
gen_func = func()
​
# 调用生成器 (生成10次)
for i in range(10):
    res = next(gen_func)
    print(res)
    
# 再次生成从上一次停止位置开始执行
res = next(gen_func)
print(res)
​
# 重置生成器
gen_func1 = func()

  

2.1.2 send 方法

"""
next 和 send 区别:
    next 只能取值
    send 不但能取值,还能发送值
send 注意点:
    第一个 send 不能给 yield 传值 默认只能写None
    最后一个yield 接受不到send的发送值
    send 是给上一个yield发送值
"""
​
# 示例
def func():
    print("process start")
    
    res = yield 100
    print(res,"内部打印1")
    
    res = yield 200
    print(res,"内部打印2")
    
    res = yield 300
    print(res,"内部打印3")
    
    print("process end")
​
# 初始化生成器函数  
gen_func = func()
​
# 调用生成器
res = gen_func.send(None)              #  process start    生成器刚启动,send 无法给上一个 yield 传值
print(res)                             # 打印第一个 yield 返回值 100
​
res = gen_func.send(500)               # send 将500传给上一个 yield 也就是 res = 500 ,内部打印1
print(res)                             # 打印第二个 yield 返回值 200

  

2.1.3 yield from 方法

# 返回值:将一个可迭代对象变成一个迭代器
def func()
    yield from [i for i in range(10)]
    
# 初始化生成器函数  
gen_func = func()
​
# 调用
for i in gen_func:
    print(i)

  

2.2 生成器表达式

# (var for var in iterable)
res = (i for i in range(500))
print(list(res))

  

3、迭代器调用的方式

# 方式一 next()   (手动触发,一次取一值)
# 方式二 __iter__ (解释器自动除发,不推荐使用)
# 方式三 for      (遍历,当数量大时,需控制好遍历数量)
# 方式四 强转      (list等)

  

 

原文地址:https://www.cnblogs.com/zhoulangshunxinyangfan/p/13360279.html