python 生成器与迭代器 - Shuang0420/Shuang0420.github.io GitHub Wiki
在Python里面,可迭代对象(iterable)和迭代器(iterator)有着特殊的含义。
一个iterable指的就是一个对象:它要么是定义了一个返回一个迭代器(iterator)的__iter__方法, 那么就是定义了一个可下标访问元素的__getitem__方法,下标从0开始,并且下标不合法的时候抛出IndexError异常。 也就是说就算一个对象没有定义__iter__方法,但是定义了__getitem__方法的话还是可以,python里面的str对象就是个很好的例子。
而iterator定义就比较简单,它就是一个定义了next(Python 2)或者__next__(Python 3)方法的对象。 这个对象会记住迭代操作的状态,每次调用__next__方法时,会将状态值更新指向下一个迭代值。
当你使用一个for循环或者map,或着一个列表推导,那么会自动调用next方法自动从迭代器(iterator)中获取每一个元素,从而完成迭代过程。
在一个iterable对象上执行iter会返回一个iterator对象, 比如iter(obj)。
eg.
>>> s = 'cat' # s is an ITERABLE
# s is a str object that is immutable
# s has no state
# s has a __getitem__() method
>>> t = iter(s) # t is an ITERATOR
# t has state (it starts by pointing at the "c")
# t has a next() method and an __iter__() method
>>> next(t) # the next() function returns the next value and advances the state
'c'
>>> next(t) # the next() function returns the next value and advances
'a'
>>> next(t) # the next() function returns the next value and advances
't'
>>> next(t) # next() raises StopIteration to signal that iteration is complete
Traceback (most recent call last):
...
StopIteration
>>> iter(t) is t # the iterator is self-iterable
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。然而我们可以把list、dict、str等Iterable变成Iterator可以使用iter()函数
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
-
凡是可作用于for循环的对象都是Iterable类型;
-
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
-
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
-
Python的for循环本质上就是通过不断调用next()函数实现的
当我们调用一个普通的函数时,执行过程从第一条语句开始,直到碰到一个return语句或者遇到一个异常抛出,再或者到了函数最后一条语句(实际上相对于一个隐式的return None)的时候结束。 一旦这个函数返回后将控制权交还给它的调用者,它里面所有的局部变量值都消失了,当你重新调用它的时候,一切又将重新开始。
这就是我们通常意义上面所认识的函数(或者说是子程序),但有时候我们需要创建某个函数,它并不简单的返回一个值,而是可以不断的yield一个值的序列。那么这个特殊的函数就需要能够“保存”它的状态。return表明函数将控制权返回给被调用时的那个点。而yield表示这个控制权的转义只是暂时的,将来我还可以重获控制权。在Python中,有这种能力的“函数”被称为生成器,它们相当有用。生成器(yield语句)刚开始被引入进来主要是用来方便的生成序列值。
一个生成器函数定义跟普通函数类似,唯一区别是,它通过yield关键字生产数据,而不是用return关键字返回。 如果在一个def函数定义内有出现了一个yield关键字,那么这个函数就变成了生成器函数(就算它还包含return语句)。
生成器函数可创建生成器迭代器,其实就是我们通常所说的生成器。生成器是一类特殊的迭代器。要成为一个迭代器,生成器就必须定义一些特殊方法,其中一个就是__next__(), 要从生成器中获取下一个元素,我们使用同样的内置函数next()
因此,当你使用next()调用一个生成器的时候,生成器负责传会下一个值,它会把yield后面的值传过来。所以记住这句话:yield相对于生成器函数的return
>>> def simple_generator_function(): >>> yield 1 >>> yield 2 >>> yield 3 >>> >>> >>> >> for value in simple_generator_function(): >>> print(value) 1 2 3 >>> our_generator = simple_generator_function() >>> next(our_generator) 1 >>> next(our_generator) 2 >>> next(our_generator) 3
当生成器函数调用yield语句的时候,生成器函数的状态被冻结,所有变量值都被保存,下一条要执行的语句被记录下来,直到下一次的next()调用来临。 一旦再遇到next()调用,生成器函数就被激活,而如果next()永远不再调用,那么最后记录的状态也就被丢弃了。
- 生成器是用来生产序列的
- yield就相对于是生成器函数的return
- yield额外做的工作就是保存了生成器函数的状态
- 一个生成器是一个特殊的迭代器
- 和迭代器类似,我们可以通过在生成器上面使用next()或者是for循环来获取下一个值