从零开始的Python学习Episode 12——迭代器&生成器
生成器
列表生成式
用于快速地生成一个列表
a = [x*x for x in range(1,9)] print(a) #输出[1, 4, 9, 16, 25, 36, 49, 64]
也可以用于生成函数结果的列表
def f(n): return n**3 a = [f(x) for x in range(1,9)] print(a) #输出[1, 8, 27, 64, 125, 216, 343, 512]
迭代器
迭代器是一个带状态的对象,他能在你调用 next() 方法的时候返回容器中的下一个值,任何实现了 __next__()方法的对象都是迭代器。
拿斐波拉契数列作例子
def fib(max): L = [] n, a, b = 0, 0, 1 while n < max: L.append(b) a, b = b, a + b n = n + 1 return L
这种用法会如果max的很大的话会占用特别多的内存,导致程序卡顿。
使用迭代器可以解决复用可占空间的问题
迭代器可以通过 next() 不断返回数列的下一个数,内存占用始终为常数。
class Fib(object): def __init__(self, max): self.max = max self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def next(self): if self.n < self.max: r = self.b self.a, self.b = self.b, self.a + self.b self.n = self.n + 1 return r raise StopIteration()
生成器
生成器其实是一种特殊的迭代器。生成器(yield)既可以保持代码的简洁性,又可以减少占用内存的效果。它不需要再像上面的类一样写 __iter__() 和 __next__() 方法了,只需要一个 yiled 关键字。
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 for n in fib(5): print(n) #输出 1 1 2 3 5
yield 的作用就是把一个函数变成一个生成器,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个生成器,在 for 循环执行时,每次循环都会执行 fib 函数内部的代码,执行到 yield b 时,fib 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。看起来就好像一个函数在正常执行的过程中被 yield 中断了数次,每次中断都会通过 yield 返回当前的迭代值。
(1)send()方法
send方法可以往生成器里传值
def f(): print("ok") n = yield print(n) print("ok2") yield 2 f = f() f.send(None) f.send(1) next(f) #输出 ok Traceback (most recent call last): 1 ok2 File "D:/PyCharm Project/test/Starter/test2.py", line 10, in <module> next(f) StopIteration
send方法会把值传到yield前的对象,并往下执行到下一个yield。但当使用send之前要先用next或者用send(None)来获取yield的位置,否则无法把值传给yield。
还有一点:
在一个生成器中,如果没有return,则默认执行到函数完毕;如果遇到return,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。而for不报错的原因是内部处理了迭代结束的这种情况。
是一个带状态的对象,他能在你调用 next() 方法的时候返回容器中的下一个值,任何实现了 __next__() (python2中实现 next() )方法的对象都是迭代器