# 生成器函数
# 只要含有 yield 关键字的函数都是生成器函数
# yield 不能和 return 共用且需要写在函数内
# 生成器函数:执行之后会得到一个生成器作为返回值
# 生成器既含有 __next__ 方法,也含有 __iter__ 方法,所以生成器也是一个迭代器,可以使用 __next__ 方法获取下一个值,也可以通过 for 循环取值
# yield和return一样,都可以返回一个值,但是 return 在返回值之后就直接结束一个函数,而 yield 不会
def generator(): '''含有yield,它是一个生成器函数''' print(1) yield 'a' ret = generator() print(ret) print(ret.__next__()) ''' <generator object generator at 0x02FCF8D0> 1 a '''
# 如果我想生成2000000个哇哈哈,用生成器,每生成一个,就返回一个,这样就不会出现内存不足的问题
def wahaha(): for i in range(2000000): yield '哇哈哈%s' % i g = wahaha() for i in g: print(i)
# send 获取下一个值的效果和 next 基本一致
# 只是在获取下一个值的时候,给上一个 yield 的位置传递一个数据
# 使用 send 的注意事项
# 第一次使用生成器的时候 是用 next 获取下一个值
# 最后一个 yield 不能接受外部的值
def generator(): print(123) content = yield 1 print('=======', content) print(456) arg = yield 2 g = generator() ret = g.__next__() print('***', ret) ret = g.send('hello') # send的效果和next一样 print('***', ret) ''' 123 *** 1 ======= hello 456 *** 2 '''
# 获取移动平均值
# 10 20 30 10
# 10 15 20 17.5
# avg = sum/count
def average(): sum = 0 count = 0 avg = 0 while True: num = yield avg sum += num # 10 count += 1 # 1 avg = sum/count avg_g = average() avg_g.__next__() avg1 = avg_g.send(10) avg1 = avg_g.send(20) avg1 = avg_g.send(30) print(avg1)
# 预激生成器的装饰器
def init(func): # 装饰器 def inner(*args,**kwargs): g = func(*args,**kwargs) # g = average() g.__next__() return g return inner @init def average(): sum = 0 count = 0 avg = 0 while True: num = yield avg sum += num # 10 count += 1 # 1 avg = sum/count avg_g = average() # ===> inner ret = avg_g.send(10) print(ret) ret = avg_g.send(20) print(ret)
# python 3 新特性
# python 2 # def generator(): # a = 'abcde' # b = '12345' # for i in a: # yield i # for i in b: # yield i # python 3 def generator(): a = 'abcde' b = '12345' yield from a yield from b g = generator() for i in g: print(i) ''' a b c d e 1 2 3 4 5 '''
# 生成器表达式
# 列表推导式 print([i*i for i in range(10)]) # 生成器表达式 print(i for i in range(10)) ''' [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] <generator object <genexpr> at 0x0120FAB0> '''
# 生成器面试题
# 面试题1
def demo(): for i in range(4): yield i # 生成器都是惰性执行的,只有要它执行的时候它才会去执行 g = demo() # 生成器对象 g1 = (i for i in g) g2 = (i for i in g1) print(list(g1)) # list(g1)把g1当中所有的内容取出来 print(list(g2)) # g1执行完之后已经空了,所以list(g2)为空列表 ''' [0, 1, 2, 3] [] '''
# 面试题2
def add(n, i): return n+i def test(): for i in range(4): yield i g = test() for n in [1, 10]: g = (add(n, i) for i in g) # 从上到下,一直到这里,生成器都没有取过值 '''相当于 n = 1 g = (add(n, i) for i in g) n = 10 g = (add(n, i) for i in (add(n, i) for i in test())) 这里,n = 10,而不是 n = 1,既 g = (add(10, i) for i in (add(10, i) for i in [0, 1, 2, 3])) 所以,最后结果为 [20, 21, 22, 23] ''' print(list(g)) # 在这里,生成器才开始取值 # [20, 21, 22, 23]