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

迭代器和生成器之间有什么区别? 当你使用每个案例时的一些例子会很有帮助。


iterator是更一般的概念:任何对象的类具有next方法( __next__在Python 3)和__iter__ ,做方法return self

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

当你需要一个具有复杂的状态维护行为的类,或者想要暴露除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):
       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

如果您在应用程序中对这些额外功能有任何实际需求。


迭代器和生成器之间有什么区别? 当你使用每个案例时的一些例子会很有帮助。

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

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

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

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

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

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

生成器是一个迭代器

具体而言,生成器是迭代器的子类型。

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

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

迭代器的一些例子是元组,列表,集合,字典,字符串和范围对象:

>>> 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函数从内建对象(或自定义对象)获取迭代器:

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

__iter__函数是当您尝试使用for循环的对象时调用的函数。 然后在迭代器对象上调用__next__next来为循环获取每个项目。 迭代器在耗尽时引发StopIteration ,并且在那时不能重用。

从文档:

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

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

(强调添加。)

因此,我们从中了解到,生成器是一种(方便)类型的迭代器。

示例迭代器对象

您可以通过创建或扩展自己的对象来创建实现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, 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 Iterator或考虑Generator Generator的函数。

最后,请注意,生成器提供了更多的协同功能。 我在“我的收益”关键字的作用是什么?“的基础上深入解释了生成器以及yield单词。


迭代器:

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

发电机:

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

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

当一个生成器函数被调用时,它会返回一个生成器对象,甚至不会开始执行该函数。 当第一次调用next()方法时,该函数开始执行,直到它返回yield语句,该语句返回所产生的值。 收益率跟踪即记得上次执行。 第二个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
>>>
链接地址: http://www.djcxy.com/p/53473.html

上一篇: Difference between Python's Generators and Iterators

下一篇: How to loop through all but the last item of a list?