列表生成式
a = [i+1 for i in range(10)] print(a)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
这就是列表生成式
生成器(generator)
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。
如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的 list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(generator)。
# 列表生成式: L = [x * x for x in range(10)] print(L) # 生成器: g = (x * x for x in range(10)) print(g)
输出结果:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x00000267824C0258>
list可以直接打印出结果,但是generator只能通过next()获得下一个返回值
g = (x * x for x in range(4)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g))
输出结果:
0
1
4
9
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
生成器示例:
def fib(max_n): # 斐波那契数列生成器 n, a, b = 0, 0, 1 while n < max_n: yield b # 函数中出现yield则函数变成生成器 a, b = b, a+b n = n+1 return "done" f = fib(6) print(f.__next__()) # 生成器生成一个数(f.__next__()=next(f)) print("______") # 生成器无法返回,之后生成的数据不包含以上的数 while True: try: x = next(f) # 循环生成数列 print("f:", x) # 输出计算结果 except StopIteration as e: # 当循环次数大于max_n时,运行以下 print("Generator return value:", e.value) break
输出结果:
1
______
f: 1
f: 2
f: 3
f: 5
f: 8
当函数中出现 ‘yield’ 时这个函数就成了一个 generator 的函数
generator在执行的时候遇到 yield 时会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
通过yield实现在单线程的情况下实现并发运算的效果:
import time def consumer(name): print("%s开始吃包子了" % name) while True: produce = yield # 函数在此暂停,等待唤醒 print("%s吃了%i个包子" % (name, produce+1)) # 唤醒后执行 def producer(name): c = consumer("A") c2 = consumer("B") c.__next__() c2.__next__() print("%s准备开始生产" % name) for i in range(3): time.sleep(1) print("已经做了%i个包子" % (i+1)) c.send(i) # 将i发送给produce,并唤醒函数 c2.send(i) producer("C")
输出结果:
A开始吃包子了
B开始吃包子了
C准备开始生产
已经做了1个包子
A吃了1个包子
B吃了1个包子
已经做了2个包子
A吃了2个包子
B吃了2个包子
已经做了3个包子
A吃了3个包子
B吃了3个包子
在 producer 函数中 c 和 c2 轮流调用 consumer 函数
send() 和 next() 一样可以唤醒生成器,而且还能给 yield 传值
迭代器
我们已经知道,可以直接作用于for循环的数据类型有以下几种:
- 一类是集合数据类型,如list、tuple、dict、set、str等;
- 一类是generator,包括生成器和带 yield 的 generator function。
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable。
可以使用isinstance()判断一个对象是否是Iterable对象
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了。
*可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator.
生成器都是Iterator对象,但list、dict、str 虽然是 Iterable ,却不是Iterator。
把list、dict、str 等 Iterable 变成Iterator可以使用 iter() 函数.
原文地址:https://www.cnblogs.com/dbf-/p/10574741.html