- 列表生成式
s = [x*2 for x in range(10)] print(s)
生成一个列表
- 生成器
s = (x*2 for x in range(5))
print(s) # <generator object <genexpr> at 0x000002942F46CA20>
创建了一个生成器,但只是一个生成器,生成器里并没有内容。(如果说列表生成式是厨师做了十道菜,这十道菜已经做出来了,占用了空间,那么生成器就是只有厨师,厨师可以做这十道菜,但是还没做,而且厨师只能按照顺序一道一道地做这十道菜,不能不按照顺序做。)
“做这些菜”的操作是next()方法,每调用一次就做一次。做完了还调用就会报错。
print(s.__next__()) # 不建议这样调用
print(next(s)) # 等价于s.__next__() in Py2: s.next() 打印0
print(next(s)) # 打印2
print(next(s)) # 打印4
print(next(s))
print(next(s))
print(next(s)) # 报错 StopIteration
也可以通过 for循环来获取这些“菜”,生成器是一个可迭代对象。
生成器就是一个可迭代对象(iterable)
for i in s:
print(i)
3. 通过创建一个生成器函数的方式创建生成器
创建一个生成器(生成器实际上就是一个函数)
def foo():
print('ok')
yield 1 # 类似于return的功能,把1返回
print('ok2')
yield 2
return None
foo()就是一个生成器对象
print(foo()) # <generator object foo at 0x00000274292E7B88> 没有打印出来'ok'
g = foo() # 这一句的作用就是创建了一个生成器对象
next(g)
next(g)
需要注意的是,运行上述代码,只会打印‘ok’和'ok2',其中的yield 的作用是返回,yield 1是返回了1,但是这个1并没有print语句打印,就像是return 1之后,需要调用print()函数才会打印出来。
a = next(g)
b = next(g)
print(a, b)
如果将上面代码的两个next(g)语句去掉,调用下面的这三条语句,实验结果如图所示,a,b是yield返回的1和2。
for i in foo():
print(i)
生成器对象foo()仍然可以通过for进行迭代。for循环后面加的都是可迭代的对象(什么是可迭代对象,只要对象拥有.__iter__()方法,该对象就是可迭代对象。)
利用生成器来实现斐波那契函数。
def fib(max):
n, before, after = 0, 0, 1
while n < max:
# print(after)
yield after
before, after = after, before+after
n = n + 1
g = fib(8)
for i in g:
print(i)
在斐波那契数列中,我们每次打印的是after,也就是说把每次计算得到的after返回就可以。但是每次返回后还要保证下一次 能够继续从该位置执行,所以用yield返回。
生成器中send的用法
def bar():
print('ok1')
count = yield 1
print(count)
print('ok2')
yield 2
b = bar()
# next(b)
s = b.send(None) # 等价于next(b) 第一次send前如果没有next,只能传一个send(None)
print(s)
ret = b.send('eee') # ret是2
print(ret)
整个流程是b=bar(),取得了生成器b,然后b.send(None)进入了bar()函数中,在yield 1处返回1给s,并打印s。b.send('eee')语句再次进入bar(),然后从count = yield 1处继续执行,yield 1 已经执行过了,所以这里从赋值开始执行,将‘eee’赋值给count并打印。然后打印‘ok2’,并返回2给ret打印。