生成器和迭代器
生成器
在上文中简单介绍了生成器的作用。在列表推导创建列表时,受到内存的限制,列表容量同样会受到限制,而且会极大的消耗空间。这时,一边循环一边计算这种机制,也就是生成器也就出现了。
创建生成器
创建生成器(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
以上就是本篇的主要内容
欢迎关注微信公众号《书所集录》
网友评论