迭代器和生成器之间的区别是什么?举一些例子来说明你在什么时候使用每种情况会很有帮助。


当前回答

iterator是一个更通用的概念:任何具有__next__方法(Python 2中的next)和__iter__方法且返回self的对象。

每个生成器都是迭代器,反之亦然。生成器是通过调用具有一个或多个yield表达式(yield语句,在Python 2.5及更早版本中)的函数来构建的,它是一个满足上一段对迭代器定义的对象。

当你需要一个具有复杂状态维护行为的类,或者想公开__next__(以及__iter__和__init__)之外的其他方法时,你可能想使用自定义迭代器,而不是生成器。大多数情况下,一个生成器(有时,对于足够简单的需求,一个生成器表达式)就足够了,而且编码更简单,因为状态维护(在合理的范围内)基本上是由框架挂起和恢复“为您完成”的。

例如,一个生成器,如:

def squares(start, stop):
    for i in range(start, stop):
        yield i * i

generator = squares(a, b)

或等效的生成器表达式(genexp)

generator = (i*i for i in range(a, b))

将需要更多的代码来构建自定义迭代器:

class Squares(object):
    def __init__(self, start, stop):
       self.start = start
       self.stop = stop
    def __iter__(self): return self
    def __next__(self): # next in Python 2
       if self.start >= self.stop:
           raise StopIteration
       current = self.start * self.start
       self.start += 1
       return current

iterator = Squares(a, b)

但是,当然,使用类Squares,你可以很容易地提供额外的方法。

def current(self):
    return self.start

如果您的应用程序中确实需要这些额外的功能。

其他回答

添加一个答案,因为现有的答案都没有专门解决官方文献中的困惑。

生成器函数是用yield而不是return定义的普通函数。当被调用时,生成器函数返回一个生成器对象,这是一种迭代器——它有一个next()方法。当调用next()时,将返回生成器函数产生的下一个值。

函数或对象都可以被称为“生成器”,这取决于你阅读的Python源文档。Python术语表表示生成器函数,而Python wiki表示生成器对象。Python教程成功地在三句话中暗示了这两种用法:

生成器是用于创建迭代器的简单而强大的工具。它们像常规函数一样编写,但在需要返回数据时使用yield语句。每次在它上调用next()时,生成器都会从停止的地方恢复(它会记住所有的数据值和最后执行的语句)。

前两句话用生成器函数标识生成器,而第三句话用生成器对象标识它们。

尽管存在这些困惑,但人们可以从Python语言参考中找到明确的最终答案:

yield表达式仅在定义生成器函数时使用,并且只能在函数定义的主体中使用。在函数定义中使用yield表达式足以导致该定义创建一个生成器函数,而不是普通函数。 当调用generator函数时,它返回一个称为generator的迭代器。然后,该生成器控制生成器函数的执行。

因此,在正式和精确的用法中,“generator”不合格指的是生成器对象,而不是生成器功能。

上面的参考资料是针对Python 2的,但Python 3语言参考资料也说了同样的事情。然而,Python 3术语表指出

发电机……通常指生成器函数,但在某些上下文中也可能指生成器迭代器。在意图不明确的情况下,使用完整的术语可以避免歧义。

无代码4行小抄:

A generator function is a function with yield in it.

A generator expression is like a list comprehension. It uses "()" vs "[]"

A generator object (often called 'a generator') is returned by both above.

A generator is also a subtype of iterator.

迭代器是使用next()方法获取序列的以下值的对象。

生成器是使用yield关键字生成或生成值序列的函数。

由生成器函数(下面的ex: foo())返回的生成器对象(下面的ex: f)上的每个next()方法调用,都会生成序列中的下一个值。

当调用生成器函数时,它返回一个生成器对象,甚至不需要开始执行该函数。当第一次调用next()方法时,函数开始执行,直到到达yield语句,该语句返回yield值。收益率会跟踪发生了什么,也就是说,它会记住最后一次执行。其次,next()调用从前一个值开始。

下面的示例演示生成器对象上yield和对next方法的调用之间的相互作用。

>>> def foo():
...     print("begin")
...     for i in range(3):
...         print("before yield", i)
...         yield i
...         print("after yield", i)
...     print("end")
...
>>> f = foo()
>>> next(f)
begin
before yield 0            # Control is in for loop
0
>>> next(f)
after yield 0             
before yield 1            # Continue for loop
1
>>> next(f)
after yield 1
before yield 2
2
>>> next(f)
after yield 2
end
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

迭代器和生成器之间的区别是什么?举一些例子来说明你在什么时候使用每种情况会很有帮助。

总结:迭代器是具有__iter__和__next__ (Python 2中的next)方法的对象。生成器提供了一种简单的内置方法来创建iterator实例。

包含yield的函数仍然是一个函数,当调用它时,返回一个生成器对象的实例:

def a_function():
    "when called, returns generator object"
    yield

生成器表达式也返回一个生成器:

a_generator = (i for i in range(0))

有关更深入的阐述和示例,请继续阅读。

Generator是一个迭代器

具体来说,generator是迭代器的子类型。

>>> import collections, types
>>> issubclass(types.GeneratorType, collections.Iterator)
True

我们可以通过几种方式创建生成器。一种非常常见和简单的方法是使用函数。

具体来说,包含yield的函数是一个函数,当调用它时,返回一个生成器:

>>> def a_function():
        "just a function definition with yield in it"
        yield
>>> type(a_function)
<class 'function'>
>>> a_generator = a_function()  # when called
>>> type(a_generator)           # returns a generator
<class 'generator'>

生成器也是一个迭代器:

>>> isinstance(a_generator, collections.Iterator)
True

迭代器是可迭代对象

迭代器是可迭代对象,

>>> issubclass(collections.Iterator, collections.Iterable)
True

它需要一个返回迭代器的__iter__方法:

>>> collections.Iterable()
Traceback (most recent call last):
  File "<pyshell#79>", line 1, in <module>
    collections.Iterable()
TypeError: Can't instantiate abstract class Iterable with abstract methods __iter__

一些可迭代对象的例子是内置元组、列表、字典、集合、冻结集、字符串、字节字符串、字节数组、范围和memoryview:

>>> all(isinstance(element, collections.Iterable) for element in (
        (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True

迭代器需要一个next或__next__方法

在Python 2中:

>>> collections.Iterator()
Traceback (most recent call last):
  File "<pyshell#80>", line 1, in <module>
    collections.Iterator()
TypeError: Can't instantiate abstract class Iterator with abstract methods next

在Python 3中:

>>> collections.Iterator()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Iterator with abstract methods __next__

我们可以使用iter函数从内置对象(或自定义对象)中获取迭代器:

>>> all(isinstance(iter(element), collections.Iterator) for element in (
        (), [], {}, set(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True

当你试图使用for循环对象时,__iter__方法会被调用。然后在迭代器对象上调用__next__方法,为循环取出每一项。迭代器在耗尽它时抛出StopIteration,此时它不能被重用。

来自文档

从内置类型文档的迭代器类型部分的生成器类型部分:

Python的生成器提供了一种实现迭代器协议的方便方法。如果容器对象的__iter__()方法被实现为生成器,它将自动返回一个迭代器对象(技术上,一个生成器对象),提供__iter__()和next() [__next__() in python3]方法。关于生成器的更多信息可以在yield表达式的文档中找到。

(强调)。

从这里我们了解到generator是一种(方便的)迭代器类型。

迭代器对象示例

您可以通过创建或扩展自己的对象来创建实现Iterator协议的对象。

class Yes(collections.Iterator):

    def __init__(self, stop):
        self.x = 0
        self.stop = stop

    def __iter__(self):
        return self

    def next(self):
        if self.x < self.stop:
            self.x += 1
            return 'yes'
        else:
            # Iterators must raise when done, else considered broken
            raise StopIteration

    __next__ = next # Python 3 compatibility

但是简单地使用Generator更容易做到这一点:

def yes(stop):
    for _ in range(stop):
        yield 'yes'

或者更简单,生成器表达式(类似于列表推导式):

yes_expr = ('yes' for _ in range(stop))

它们都可以以同样的方式使用:

>>> stop = 4             
>>> for i, y1, y2, y3 in zip(range(stop), Yes(stop), yes(stop), 
                             ('yes' for _ in range(stop))):
...     print('{0}: {1} == {2} == {3}'.format(i, y1, y2, y3))
...     
0: yes == yes == yes
1: yes == yes == yes
2: yes == yes == yes
3: yes == yes == yes

结论

当需要将Python对象扩展为可迭代的对象时,可以直接使用Iterator协议。

然而,在绝大多数情况下,您最适合使用yield来定义返回Generator Iterator的函数或考虑Generator expression。

最后,请注意生成器作为协程提供了更多的功能。我在回答“yield”关键字做什么?”时,深入地解释了Generators和yield语句。

我用一种非常简单的方式专门为Python新手编写,尽管Python在本质上做了很多事情。

让我们从最基本的开始:

考虑一个列表,

l = [1,2,3]

让我们写一个等效函数:

def f():
    return [1,2,3]

打印(l)的O /p: [1,2,3] & O /p打印(f()): [1,2,3]

让列表l可迭代:在python中,列表总是可迭代的,这意味着你可以在任何你想要的时候应用迭代器。

让我们在list上应用迭代器:

iter_l = iter(l) # iterator applied explicitly

让我们把一个函数设为可迭代的,也就是说,写一个等效的生成器函数。 在python中,只要你引入关键字yield;它变成了一个生成器函数,迭代器将隐式应用。

注意:每个生成器在应用隐式迭代器时总是可迭代的,这里隐式迭代器是关键 因此生成器函数将是:

def f():
  yield 1 
  yield 2
  yield 3

iter_f = f() # which is iter(f) as iterator is already applied implicitly

如果你观察到,一旦你让函数f成为一个生成器,它就已经是iter(f)

Now,

L是列表,在应用迭代器方法iter后,它变成, iter(左) F已经是iter(F),在应用迭代器方法“iter”它 变成iter(iter(f))也就是iter(f)

这有点像你将int类型转换为int(x)它已经是int类型并且它将保持int(x)

例如o/p:

print(type(iter(iter(l))))

is

<class 'list_iterator'>

别忘了这是Python而不是C或c++

因此,由上述解释得出的结论是:

列出l ~= iter(l) 生成函数f == iter(f)