理解Python中的迭代、可迭代对象、迭代器、生成器、yiled专题
Iteration, Iterable, Iterator, Generator, yield in Python
迭代(Iteration)
迭代,指的是按照某种顺序逐个访问列表中的每一项。
在 Python 中,用for
来实现迭代,它的结构是 for ... in ...
,实际是利用可迭代对象Iterable
得到迭代器Iterator
,再重复调用 __next__
方法实现的。
可迭代对象(Iterable)
可迭代对象Iterable
就是实现了__iter__
方法,可以返回一个迭代器Iterator
,或者定义了__getitem__
方法,可以按index
索引(且能够在没有值时抛出一个 IndexError
异常)的任意对象。
An iterable is an object that has an
__iter__
method which returns an iterator, or which defines a__getitem__
method that can take sequential indexes starting from zero (and raises anIndexError
when the indexes are no longer valid). So an iterable is an object that you can get an iterator from.
可迭代对象具有如下的特性:
- 可以
for
循环:for i in iterable
- 可以按
index
索引:定义了__getitem__
方法,比如list,str
- 可以通过调用
__iter__
方法或者被iter(obj)
调用,返回一个迭代器Iterator
可以通过isinstance(obj, collections.Iterable)
来判断对象是否为可迭代对象。
>
NOTE:
Often, for pragmatic reasons, iterable classes will implement both__iter__()
and__next__()
in the same class, and have__iter__()
returnself
, which makes the class both an iterable and its own iterator. It is perfectly fine to return a different object as the iterator, though.
迭代器(Iterator)
迭代器Iterator
就是实现了next (Python 2)
或者 __next__ (Python 3)
方法(并且能够在没有值时抛出一个 StopIteration
异常)的任意对象。
如果需要自定义迭代器,则需要满足如下迭代器协议:
- 定义了
__iter__
方法,但是必须返回自身 - 定义了
__next__
方法。用来返回下一个值,并且当没有数据了,抛出StopIteration
- 可以保持当前的状态
可以通过 isinstance(obj, collections.Iterator)
来判断对象是否为迭代器。
生成器(Generator)
生成器Generator
是创建一个迭代器最简单的方式。在普通的函数中使用yield
代替return
,这个函数将会返回一个生成器。
生成器是可以迭代的,但是你 只可以读取它一次 ,因为它并不把所有的值放在内存中,而是实时地生成数据。
两种创建方式
包含yield
的函数(generator function)
yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器。当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象。
生成器函数跟普通函数只有一点不一样,就是把 return
换成yield
,其中yield
是一个语法糖,内部实现了迭代器协议,同时保持状态可以挂起。yield
是数据的生产者,而诸如for
等是数据的消费者。
|
|
生成器表达式(generator expression)
|
|
三个内置方法(3 build-in methods)
close()
close()
方法可以关闭生成器。生成器被关闭后,再次调用__next__()
方法,不管能否遇到yield关键字,都会立即抛出StopIteration异常。
|
|
send()
可以通过send()
方法,向生成器内部传递参数。
|
|
需要注意的是,调用send()
方法之前,必须先调用__next__()
方法或者send(None)
,让生成器执行到yield
处以接受参数。否则将抛出异常can't send non-None value to a just-started generator
。其实__next()__
的实现,就是send(None)
。
throw()
除了向生成器函数内部传递参数,我们还可以传递异常。
|
|
|
|
todo
- yield from
- Coroutine
- Asynchronous generator functions
- Awaitable, AsyncIterator, AsyncIterable
参考资料
- http://kuanghy.github.io/2016/05/18/python-iteration
- https://eastlakeside.gitbooks.io/interpy-zh/content/Generators/
- https://docs.python.org/3/tutorial/classes.html#iterators
- http://www.cnblogs.com/huxi/archive/2011/07/01/2095931.html
- https://foofish.net/iterators-vs-generators.html
- http://nvie.com/posts/iterators-vs-generators/
- http://pyzh.readthedocs.io/en/latest/the-python-yield-keyword-explained.html#id3
- http://www.bjhee.com/python-yield.html