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

isinstance()判断一个对象是否是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

isinstance()判断一个对象是否是Iterator对象

>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

把list、dict、str等Iterable变成Iterator可以使用iter()函数

生成器都是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循环来获取下一个值

来源
python核心 - 迭代器
python核心 - 生成器和yield

⚠️ **GitHub.com Fallback** ⚠️