生成器和推导式
一. 推导式
列表, 字典, 集合有推导式, 元组没有推导式
列表推导式: lst = [i for i in range(10) if i % 2 == 0]
字典推导式: dic = {k:v for k,v in func() if k>v} # def func(): yield 2,1 yield 3,1 yield 4,1 (yield 的第一个值不能相同, 因为字典的键会传不进去)
集合推导式: se = {i for i in range(5)}
a = (i for i in range(10) # 这不是元组, 这是生成器的表达式, 具有惰性.
可以用for循环, while循环, list[], tuple(), set(), 来遍历生成器
二. 生成器
生成器的本质是迭代器
生成器的特点和迭代器一样, 取值方式一样, __next__(), send(), send()可以给上一个yield传值
生成器一般由生成器函数或生成器表达式来创建
超过yield的个数会报错, 但可以用try: except StopIteration兜着
生成器函数:
和普通函数没有区别, 函数里面含有yield.
生成器函数在执行时, 默认不会执行函数, 而是返回生成器
生成器函数通过生成器的__next__()分段执行这个函数.
可以用send()给上一个yield传值, 不能在开头(没有上一个yield)
f = func()拿到的是生成器, 不会执行函数.
yield会停止执行函数, 下次再分段执行函数.
如果不使用f = func()来获取生成器, 每次用func().__next__()来获取, 每次都是获取的到第一个yield的值
def func(): a = yield 1 print(a) b = yield 2 print(b) c = yield 3 print(c) yield 4 f = func()
# ===================================== 第一个输出方法 ===================================== print(f.__next__()) print(f.send(123)) print(f.send(234)) print(f.send(345)) 输出 1 123 2 234 3 345 4
# ===================================== 第二个输出方法 ===================================== print(f.__next__(),f.send(123),f.send(234),f.send(345)) 输出: 123 234 345 1 2 3 4
生成器表达式:
gen = (i for i in range(10) if i >= 5)
gen = (func(i) for i in range(10) if i >= 5)
gen = ('xxxxx{}".format(i) for i in range(10))
特性:
惰性机制
只能向前
节省内存
题:
def func(): print(111) yield 222 yield 333 g = func() g1 = (i for i in g) # g1拿到的还生成器表达式, 不会执行表达式, 在后面的list(g1)才会执行表达式 g2 = (i for i in g) print(list(g)) # list(g)拿到的是g的所有的yield的值, 本来g是不会自动执行的, 但是list使g # 自动执行了, g执行完了以后, g是生成器, 不能回退, 所以g1和g2再执行g的时候 # 就拿不到值了 print(list(g1)) print(list(g2)) # 如果g2先执行, g2就会遍历完g中的值, list又会便利完g2的值, 所以g1再遍历g # 的值, 或者list再遍历g的值就拿不到值了
def add(a, b): return a + b def test(): for i in range(4): yield i # yield 0,1,2,3 g = test() for n in [2,10] g = (add(n, i) for i in g) # 拿到g时不会遍历生成器 print(list(g)) # ===================================== g的运行 ===================================== for n in [2,10] g = (add(n, i) for i in g) n = 2 # g = (add(n = 2, i) for i in g) # i的值现在拿不出来, 因为g没有被遍历, 所以add函数无法执行 # 所以add函数还是add(n, i) n = 10 # g = (add(n = 10, i) for i in (add(n = 10, i) for i in g)) # 由于add函数的n上次未执行, # 所以add函数还是add(n, i), 所以这次n = 10时, n就被重新 # 赋值了 list(g) # g = add(10, i) for i in (add(10, i) for i in 0.1.2.3)) # ===================================== 改一下 =====================================d def add(a, b): return a + b def test(): for i in range(4): yield i # yield 0,1,2,3 g = test() for n in [2,10] g = [add(n, i) for i in g] print(list(g)) # ===================================== g的运行 ===================================== n = 2 g = [2,3,4,5] # 列表的推导式, 不是生成器的表达式 n = 10 g = [12,13,14,15]