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


当前回答

每个人都有一个非常漂亮和冗长的答案,我真的很感激。我只是想给那些在概念上还不太清楚的人一个简短的回答:

If you create your own iterator, it is a little bit involved - you have to create a class and at least implement the iter and the next methods. But what if you don't want to go through this hassle and want to quickly create an iterator. Fortunately, Python provides a short-cut way to defining an iterator. All you need to do is define a function with at least 1 call to yield and now when you call that function it will return "something" which will act like an iterator (you can call next method and use it in a for loop). This something has a name in Python called Generator

希望这能澄清一点。

其他回答

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术语表指出

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

强烈推荐Ned Batchelder的迭代器和生成器示例

一个没有生成器的方法,它对偶数进行处理

def evens(stream):
   them = []
   for n in stream:
      if n % 2 == 0:
         them.append(n)
   return them

而通过使用发电机

def evens(stream):
    for n in stream:
        if n % 2 == 0:
            yield n

我们不需要任何列表或返回语句 有效的大/无限长的流…它只是走动并产生值

调用evens方法(生成器)和往常一样

num = [...]
for n in evens(num):
   do_smth(n)

发电机也用于打破双环

迭代器

满页的书是可迭代对象,书签是可迭代对象 迭代器

而这个书签除了下一步移动什么也做不了

litr = iter([1,2,3])
next(litr) ## 1
next(litr) ## 2
next(litr) ## 3
next(litr) ## StopIteration  (Exception) as we got end of the iterator

使用生成器…我们需要一个函数

使用迭代器…我们需要next和iter

如前所述:

Generator函数返回一个迭代器对象

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

对于相同的数据,你可以比较两种方法:

def myGeneratorList(n):
    for i in range(n):
        yield i

def myIterableList(n):
    ll = n*[None]
    for i in range(n):
        ll[i] = i
    return ll

# Same values
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)
for i1, i2 in zip(ll1, ll2):
    print("{} {}".format(i1, i2))

# Generator can only be read once
ll1 = myGeneratorList(10)
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

# Generator can be read several times if converted into iterable
ll1 = list(myGeneratorList(10))
ll2 = myIterableList(10)

print("{} {}".format(len(list(ll1)), len(ll2)))
print("{} {}".format(len(list(ll1)), len(ll2)))

此外,如果检查内存占用,生成器占用的内存要少得多,因为它不需要同时将所有值存储在内存中。