生成器和迭代器
生成器
在上文中简单介绍了生成器的作用。在列表推导创建列表时,受到内存的限制,列表容量同样会受到限制,而且会极大的消耗空间。这时,一边循环一边计算这种机制,也就是生成器也就出现了。
创建生成器
创建生成器(generator),有很多方法。其中一种,使用生成器表达式,即是将列表推导中的方括号 [] 改成圆括号 ()。
如下示例:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x000001FBFD43A048>
>>> list(g)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
由于生成器返回的结果是惰性序列,并不会直接返回想要结果,可以手动遍历,一个个进行打印:
>>> g = (x * x for x in range(10))
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> next(g)
16
>>> next(g)
25
>>> next(g)
36
>>> next(g)
49
>>> next(g)
64
>>> next(g)
81
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
调用 next() 可以返回 g 的下一个元素值,当没有更多元素的时候,会抛出 StopIteration 的错误。若只是遍历获得结果,可以使用 for 循环,因为 generator 是可迭代对象:
>>> g = (x * x for x in range(10))
>>> for i in g:
... print(i)
...
0
1
4
9
16
25
36
49
64
81
使用 for 循环遍历的时,就不需要担心 StopIteration 异常。
还有另外一种方法可以创建生成器(generator),在 Python 中,使用 yield 的函数被称为生成器(generator)函数。使用 yield 实现斐波那契数列,如下示例:
def fib(n):
ct, a, b = 0, 0, 1
while ct < n:
yield b
a, b = b, a + b
ct += 1
return "done"
生成器和普通函数执行过程有所不同。函数是顺序执行,遇到 return 会返回结果。而生成器遇到 next() 会执行,遇到 yield 返回,再次执行会直接在上次返回的 yield 继续执行。如下示例:
>>> def test():
... print("value 1")
... yield(1)
... print("value 2")
... yield(2)
... print("value 3")
... yield(3)
...
>>> t = test()
>>> next(t)
value 1
1
>>> next(t)
value 2
2
>>> next(t)
value 3
3
>>> next(t)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
上述代码中,调用 next() 后,打印 value 1,遇到 yield 输出 1,停止执行,再次执行 next() 时,在上次遇到 yield 语句停止的后面继续执行,输出 value 2 和 2,直到没有元素,抛出异常。这就是生成器函数的执行过程。
迭代器
开始迭代器的内容前,先延伸介绍一个可迭代对象的概念。可以直接作用于 for 循环的对象称为可迭代对象:Iterable 。可以用 isinstance() 进行判断:
>>> from collections import Iterable
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
可以被 next() 函数调用并不断返回下一个值得对象称为迭代器:Iterator。同样可以用 isinstance() 判断对象是否是 Iterator 对象:
>>> from collections import Iterator
>>> isinstance('abc', Iterator)
False
>>> isinstance((x for x in range(10)), Iterator)
True
可以看出,生成器也是 Iterator 对象。但 str 虽然是 Iterable,却不是 Iterator,同样的还有列表 list,字典 dict。
但 iter() 函数能够将 Iterable 变成 Iterator,例如:
>>> isinstance(iter('abc'), Iterator)
True
>>> isinstance(iter([]), Iterator)
True
创建一个迭代器
创建迭代器需要实现两个方法:__iter__() 和 __next__()。
__iter__() 方法返回一个特殊的迭代器对象,这个对象能够实现 __next__() 方法通过 StopIteration 异常标识迭代的完成。
__next__() 方法会返回下一个迭代器对象。
实现逐步加 1 的类,示例如下:
>>> class NumberIncrease():
... def __iter__(self):
... self.x = 1
... return self
... def __next__(self):
... i = self.x
... self.x += 1
... return i
...
>>> num_increase = NumberIncrease()
>>> num_iter = iter(num_increase)
>>> next(num_iter)
1
>>> next(num_iter)
2
>>> next(num_iter)
3
>>> next(num_iter)
4
>>> next(num_iter)
5
以上就是本篇的主要内容
随时随地看视频