Python的生成器和迭代器之间的区别

迭代器和生成器有什么区别? 当你使用每个案例的一些例子将是有帮助的。

iterator是一个更一般的概念:任何对象的类都有next方法(Python 3中的__iter__ )和一个return self__iter__方法。

每个生成器都是一个迭代器,但不是相反的。 通过调用具有一个或多个yieldexpression式(在Python 2.5和更早版本中为yield语句)的函数来构build生成器,并且该对象符合上一个iterator的定义。

当你需要一个具有复杂的状态维护行为的类,或者想要暴露除next之外的其他方法(以及__iter____init__ )时,你可能需要使用自定义迭代器而不是生成器。 大多数情况下,一个生成器(有时足够简单的需求,一个生成器expression式 )就足够了,而且编码更简单,因为状态维护(在合理范围内)基本上是由框架暂停和恢复完成的。

例如,一个生成器如:

 def squares(start, stop): for i in range(start, stop): yield i * i generator = squares(a, b) 

或等价的生成器expression式(genexp)

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

将需要更多代码构build为自定义迭代器:

 class Squares(object): def __init__(self, start, stop): self.start = start self.stop = stop def __iter__(self): return self def next(self): 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 

如果您在应用程序中有任何实际需要这种额外的function。

迭代器和生成器有什么区别? 当你使用每个案例的一些例子将是有帮助的。

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

带有yield的函数仍然是一个函数,在调用时返回一个生成器对象的实例:

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

生成器expression式也返回一个生成器:

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

为了更深入的阐述和例子,请继续阅读。

生成器一个迭代器

具体而言,生成器是迭代器的一个子types。

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

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

具体来说,一个带有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 

这需要返回一个Iterator的__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__ 

iterables的一些例子是元组,列表,集合,字典,string和范围对象:

 >>> all(isinstance(element, collections.Iterable) for element in ( (), [], {}, set(), '', range(0))) 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函数从内build对象(或自定义对象)获取迭代器:

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

__iter__函数是当你试图用for循环来使用一个对象时被调用的函数。 然后在迭代器对象上调用__next__next来获取每个项目的循环。 迭代器在耗尽之后会引发StopIteration ,并且在此时不能重用。

从文档:

从“内置types” 文档的“迭代器types”部分的“生成器types”部分:

Python的生成器提供了一个实现迭代器协议的简便方法。 如果一个容器对象的__iter__()方法被实现为一个生成器,它将自动返回一个在Python 3中提供__iter__()next() [ __next__() __iter__()方法的迭代器对象(技术上讲,一个生成器对象)。 有关生成器的更多信息可以在yieldexpression式的文档中find。

(强调补充说。)

所以从这里我们知道生成器是一个(方便的)types的迭代器。

示例迭代器对象

您可以通过创build或扩展自己的对象来创build实现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' 

或者也许更简单,一个生成器expression式(类似于列表parsing):

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

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

 >>> stop = 4 >>> for i, ys in enumerate(zip(Yes(stop), yes(stop), ('yes' for _ in range(stop))): >>> 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的函数,或者考虑使用Generator Expressions。

最后,请注意,生成器提供了更多的协同function。 我在“我的收益”关键字的作用是什么?

迭代器:

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

发电机:

生成器是使用yield方法生成或生成一系列值的函数。

每个next()方法调用generator函数返回的generator对象(例如下例中的ex: f )(例如下例中的ex: foo()函数),依次生成下一个值。

当一个生成器函数被调用时,它将返回一个生成器对象,而不会开始执行该函数。 当第一次调用next()方法时,函数开始执行,直到达到yield语句,返回yield值。 产量跟踪logging最后的执行。 第二个next()调用从以前的值继续。

以下示例演示了yield和调用发生器对象的下一个方法之间的相互作用。

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

添加一个答案,因为没有任何现有的答案专门处理官方文献中的混乱。

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

函数或对象可以被称为“生成器”,具体取决于您读取的Python源文档。 Python的词汇表说生成器函数,而Python的wiki意味着生成器对象。 Python教程显着地设法暗示这两个用法在三个句子的空间:

生成器是创build迭代器的简单而强大的工具。 它们像常规函数一样编写,但是只要他们想返回数据就使用yield语句。 每当next()被调用时,生成器会从停止的地方恢复(它会记住所有的数据值以及上次执行的语句)。

前两个句子用发电机function标识发电机,而第三个句子用发电机对象标识它们。

尽pipe所有这些困惑,人们可以找出明确的最后一句话的Python语言参考 :

yieldexpression式仅在定义生成器函数时使用,并且只能在函数定义的主体中使用。 在函数定义中使用yieldexpression式足以导致该定义创build生成器函数,而不是正常函数。

当调用生成器函数时,它将返回一个称为生成器的迭代器。 该生成器然后控制生成器函数的执行。

因此,在forms和精确的使用中, “发电机”不合格是指发电机对象,而不是发电机function。

上面的引用是针对Python 2的,但是Python 3的语言引用也是一样的。 但是, Python 3术语表明

生成器 …通常是指生成器函数,但在某些上下文中可能指的是生成器迭代器。 在意图不明确的情况下,使用完整的术语避免含糊不清。

发电机function,发电机对象,发电机:

Generator函数就像Python中的常规函数​​,但它包含一个或多个yield语句。 生成器函数是创buildIterator对象的一个​​很好的工具。 由生成器函数returend的Iterator对象也被称为Generator对象Generator

在这个例子中,我创build了一个Generator函数,它返回一个Generator对象<generator object fib at 0x01342480> 。 就像其他的迭代器一样,Generator对象可以在for循环中使用,或者使用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 

所以一个生成器函数是创build一个Iterator对象的最简单的方法。

迭代器

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

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

 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 

每个人都有一个非常好的和详细的答案与例子,我真的很感激它。 我只是想给那些概念上还不太清楚的人提供一些简短的答案:

如果你创build你自己的迭代器,那么它有一点涉及 – 你必须创build一个类,至less实现iter和下一个方法。 但是,如果你不想经历这个麻烦,并想快速创build一个迭代器。 幸运的是,Python提供了定义迭代器的捷径。 所有你需要做的就是定义一个至less有一个调用的函数来产生,现在当你调用这个函数的时候,它会返回一些类似迭代器的东西(你可以调用下一个方法并在for循环中使用它)。 这个东西在Python中有一个叫做Generator的名字

希望澄清一下。

您可以比较两种方法的相同数据:

 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))) 

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