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


当前回答

生成器函数,生成器对象,生成器:

Generator函数就像Python中的常规函数一样,但它包含一个或多个yield语句。Generator函数是一个很好的工具,可以尽可能简单地创建Iterator对象。generator函数返回的Iterator对象也称为generator对象或generator。

在这个例子中,我创建了一个Generator函数,它返回一个Generator对象< Generator对象fib at 0x01342480>。就像其他迭代器一样,Generator对象可以在for循环中使用,也可以与从Generator返回下一个值的内置函数next()一起使用。

def fib(max):
    a, b = 0, 1
    for i in range(max):
        yield a
        a, b = b, a + b
print(fib(10))             #<generator object fib at 0x01342480>

for i in fib(10):
    print(i)               # 0 1 1 2 3 5 8 13 21 34


print(next(myfib))         #0
print(next(myfib))         #1
print(next(myfib))         #1
print(next(myfib))         #2

因此,生成器函数是创建Iterator对象的最简单方法。

迭代器:

每个生成器对象都是迭代器,反之亦然。如果自定义迭代器对象的类实现了__iter__和__next__方法(也称为迭代器协议),则可以创建自定义迭代器对象。

然而,使用生成器函数来创建迭代器要容易得多,因为它们简化了迭代器的创建,但是自定义迭代器给了你更多的自由,你也可以根据你的需求实现其他方法,如下面的例子所示。

class Fib:
    def __init__(self,max):
        self.current=0
        self.next=1
        self.max=max
        self.count=0

    def __iter__(self):
        return self

    def __next__(self):
        if self.count>self.max:
            raise StopIteration
        else:
            self.current,self.next=self.next,(self.current+self.next)
            self.count+=1
            return self.next-self.current

    def __str__(self):
        return "Generator object"

itobj=Fib(4)
print(itobj)               #Generator object

for i in Fib(4):  
    print(i)               #0 1 1 2

print(next(itobj))         #0
print(next(itobj))         #1
print(next(itobj))         #1

其他回答

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

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

希望这能澄清一点。

强烈推荐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的全部好处:

每次在内存中存储一个元素

之前的回答忽略了这一点:生成器有close方法,而典型的迭代器没有。close方法在生成器中触发StopIteration异常,该异常可能在迭代器中的finally子句中被捕获,以获得运行一些清理的机会。这种抽象使得它在大型迭代器中比简单迭代器更有用。可以像关闭文件一样关闭生成器,而不必担心下面有什么。

也就是说,我个人对第一个问题的回答是:iteratable只有__iter__方法,典型的迭代器只有__next__方法,生成器既有__iter__又有__next__,还有一个附加的close。

For the second question, my personal answer would be: in a public interface, I tend to favor generators a lot, since it’s more resilient: the close method an a greater composability with yield from. Locally, I may use iterators, but only if it’s a flat and simple structure (iterators does not compose easily) and if there are reasons to believe the sequence is rather short especially if it may be stopped before it reach the end. I tend to look at iterators as a low level primitive, except as literals.

对于控制流而言,生成器是一个与承诺同样重要的概念:两者都是抽象的和可组合的。

这篇文章涵盖了两者之间的许多细节差异,但想在两者之间的概念差异上添加一些东西:

[…GoF书中定义的迭代器从集合中检索项,而生成器可以“凭空”生成项。这就是为什么斐波那契序列生成器是一个常见的例子:无限级数的数字不能存储在一个集合中。

Ramalho,卢西亚诺。流利的Python(第415页)。O ' reilly媒体。Kindle版。

当然,它并没有涵盖所有的方面,但我认为它给出了一个很好的概念,当一个人是有用的。

我用一种非常简单的方式专门为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)