生成器本质上也是一个迭代器,我的一点理解的话,它也有点像只能执行一轮的单链表,通过 obj.__next__()就获得了当前指针(并不是真的指针)的指向值,同时将将指针指向一下个,过程不可逆,最后一个元素执行完之后这个生成器基本上就没法用了。
-
首先看一个普通函数
# 一个普通函数 def generator1(): print(1) return 'a' ret = generator1() print(ret) # 1 # a
-
一个生成器函数
def generator2(): print(1) yield 'a' # 有yield,这是一个生成器函数 # #生成器函数 : 执行之后会得到一个生成器作为返回值 ret = generator2() # 生成器对象 print(ret) # <generator object generator at 0x00000196912B14C8> print(ret.__next__()) # 通过.__next__才能取值 # 1 # a
通过关键字
yield
来返回值的函数是一个生成器函数yield
和return
不能同时出现在同一个函数中 -
薛微复杂一点的生成器函数
print(1) yield 'a' print(2) yield 'b' yield 'c' # print('最后一个yield之后的操作') # 在最后一个yield之后不允许在有操作,解决方法见下文 g = generator3() ret = g.__next__() print(ret) # 1 # a ret = g.__next__() print(ret) # 2 # b ret = g.__next__() print(ret) # c # print(g.__next__()) # 报错,在最后一个yield之后在进行next操作报错
-
生成器——send方法
生成器.send()
方法的做事是与生成器进行交互,对生成器传值在这里还给出了 在最后一个yield之后继续操作的 的方式
def generator4(): print(123) content = yield 1 # 这个yield返回之后,执行send操作,赋值给content print('=======', content) print(456) arg = yield '这是实际用到的最后一个yield了' print('这里是最后一个yield之后的一些操作') # 最后一个yield之后不应再有操作,否则报错 # 可以把最后一个yield写成上面的形式(用一个变量来接收是为了支持send),最后再加一个yield空值 yield g = generator4() ret = g.__next__() print('***', ret) ret = g.send('hello') # send的效果和next一样,都会返回yield的值 print('***', ret) # 123 # *** 1 # ======= hello # 456 # *** 2
send 获取下一个值的效果和next基本一致,也会返回yield的值;
只是在获取下一个值的时候,给上一yield的接受位置传递一个数据(所以在send之前,一定要有一次返回yield的操作(即一次next))
最后一个yield不能接受外部的值 -
添加装饰器(承接上一段代码)
看到在生成器在使用时,需要进行一步没有实用__next__的操作,如果写了一两个生成器,每次追加一步__next__操作还可以接受,但是如果很多的话就不免麻烦了,通过设置装饰器的方式可以统一为这些函数加上__next__
# 预激生成器的装饰器(承接上一个函数,就是用装饰器做了__next__的操作,下面用的时候可以直接send) def init(func): #装饰器 def inner(*args,**kwargs): g = func(*args,**kwargs) #g = average() g.__next__() return g return inner @init def generator4(): print(123) content = yield 1 # 这个yield返回之后,执行send操作,赋值给content print('=======', content) print(456) arg = yield '这是实际用到的最后一个yield了' print('这里是最后一个yield之后的一些操作') # 最后一个yield之后不应再有操作,否则报错 # 可以把最后一个yield写成上面的形式(用一个变量来接收是为了支持send),最后再加一个yield空值 yield g = generator4() ret = g.send('hello') # send的效果和next一样,都会返回yield的值 print('***', ret) # 123 # ======= hello # 456 # *** 这是实际用到的最后一个yield了
-
yield from
在python3中,出现了一种yield from的新写法,感觉它就行for i in xxx一样是个方便的用来遍历的操作
# 普通写法 def generator5(): a = 'abcde' b = '12345' for i in a: yield i for i in b: yield i # yield from写法 def generator6(): a = 'abcde' b = '12345' yield from a yield from b g5 = generator5() for i in g5: print(i, end=' ') print() # a b c d e 1 2 3 4 5 g6 = generator6() for i in g6: print(i, end=' ') print() # a b c d e 1 2 3 4 5
-
参考文献