Python的生成器和迭代器之间的差异

时间:2022-06-30 04:00:04

What is the difference between iterators and generators? Some examples for when you would use each case would be helpful.

迭代器和生成器的区别是什么?当你使用每一种情况时,一些例子会很有帮助。

8 个解决方案

#1


395  

iterator is a more general concept: any object whose class has a next method (__next__ in Python 3) and an __iter__ method that does return self.

迭代器是一个更一般的概念:任何具有下一个方法(Python 3中的__next__)和一个返回self的__iter__方法的对象。

Every generator is an iterator, but not vice versa. A generator is built by calling a function that has one or more yield expressions (yield statements, in Python 2.5 and earlier), and is an object that meets the previous paragraph's definition of an iterator.

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

You may want to use a custom iterator, rather than a generator, when you need a class with somewhat complex state-maintaining behavior, or want to expose other methods besides next (and __iter__ and __init__). Most often, a generator (sometimes, for sufficiently simple needs, a generator expression) is sufficient, and it's simpler to code because state maintenance (within reasonable limits) is basically "done for you" by the frame getting suspended and resumed.

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

For example, a generator such as:

例如,生成器如:

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

generator = squares(a, b)

or the equivalent generator expression (genexp)

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

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

would take more code to build as a custom iterator:

需要更多的代码来作为定制迭代器构建:

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)

But, of course, with class Squares you could easily offer extra methods, i.e.

但是,当然,有了类平方,您可以很容易地提供额外的方法,例如。

    def current(self):
       return self.start

if you have any actual need for such extra functionality in your application.

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

#2


66  

What is the difference between iterators and generators? Some examples for when you would use each case would be helpful.

In summary: Iterators are objects that have an __iter__ and a __next__ (next in Python 2) method. Generators provide an easy, built-in way to create instances of Iterators.

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

A function with yield in it is still a function, that, when called, returns an instance of a generator object:

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

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

A generator expression also returns a generator:

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

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

For a more in-depth exposition and examples, keep reading.

要获得更深入的阐述和示例,请继续阅读。

A Generator is an Iterator

Specifically, generator is a subtype of iterator.

具体来说,generator是iterator的一种子类型。

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

We can create a generator several ways. A very common and simple way to do so is with a function.

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

Specifically, a function with yield in it is a function, that, when called, returns a generator:

具体地说,含有屈服的函数是一个函数,当调用它时,返回一个生成器:

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

And a generator, again, is an Iterator:

生成器也是迭代器:

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

An Iterator is an Iterable

An Iterator is an Iterable,

迭代器是可迭代的,

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

which requires an __iter__ method that returns an 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__

Some examples of iterables are tuples, lists, sets, dicts, strings, and range objects:

可以迭代的例子有元组、列表、集合、句柄、字符串和范围对象:

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

Iterators require a next or __next__ method

In Python 2:

在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

And in Python 3:

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

We can get the iterators from the builtin objects (or custom objects) with the iter function:

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

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

The __iter__ function is what is invoked when you attempt to use an object with a for-loop. Then __next__ or next is called on the iterator object to get each item out for the loop. The iterator raises StopIteration when you have exhausted it, and it cannot be reused at that point.

__iter__函数是在尝试使用带有for循环的对象时调用的函数。然后在iterator对象上调用__next__或next来获取循环的每个项。当您耗尽迭代时,迭代器将引发StopIteration,此时不能重用它。

From the docs:

From the Generator Types section of the Iterator Types section of the Built-in Types documentation:

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

Python’s generators provide a convenient way to implement the iterator protocol. If a container object’s __iter__() method is implemented as a generator, it will automatically return an iterator object (technically, a generator object) supplying the __iter__() and next() [__next__() in Python 3] methods. More information about generators can be found in the documentation for the yield expression.

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

(Emphasis added.)

(强调)。

So from this we learn that Generators are a (convenient) type of Iterator.

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

Example Iterator Objects

You might create object that implements the Iterator protocol by creating or extending your own object.

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

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

But it's easier to simply use a Generator to do this:

但是简单地使用一个生成器就可以做到这一点:

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

Or perhaps simpler, a Generator Expression (works similarly to list comprehensions):

或者更简单,一个生成器表达式(类似于列表理解的工作):

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

They can all be used in the same way:

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

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

Conclusion

You can use the Iterator protocol directly when you need to extend a Python object as an object that can be iterated over.

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

However, in the vast majority of cases, you are best suited to use yield to define a function that returns a Generator Iterator or consider Generator Expressions.

但是,在绝大多数情况下,您最适合使用yield来定义返回生成器迭代器或考虑生成器表达式的函数。

Finally, note that generators provide even more functionality as coroutines. I explain Generators, along with the yield statement, in depth on my answer to "What does the “yield” keyword do?".

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

#3


27  

Iterators:

迭代器:

Iterator are objects which uses next() method to get next value of sequence.

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

Generators:

发电机:

A generator is a function that produces or yields a sequence of values using yield method.

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

Every next() method call on generator object(for ex: f as in below example) returned by generator function(for ex: foo() function in below example), generates next value in sequence.

生成器函数(例:f)返回的每一个next()方法调用(例:foo()函数)都按顺序生成下一个值。

When a generator function is called, it returns an generator object without even beginning execution of the function. When next() method is called for the first time, the function starts executing until it reaches yield statement which returns the yielded value. The yield keeps track of i.e. remembers last execution. And second next() call continues from previous value.

当调用生成器函数时,它返回一个生成器对象,而不需要开始执行该函数。当第一次调用next()方法时,函数开始执行,直到到达yield语句,该语句返回yield值。收益率跟踪即记住最后一次执行。第二个next()调用从先前的值继续。

The following example demonstrates the interplay between yield and call to next method on generator object.

下面的例子演示了在生成器对象上的下一个方法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
>>>

#4


14  

Adding an answer because none of the existing answers specifically address the confusion in the official literature.

添加一个答案,因为现有的答案中没有一个明确地解决了官方文献中的困惑。

Generator functions are ordinary functions defined using yield instead of return. When called, a generator function returns a generator object, which is a kind of iterator - it has a next() method. When you call next(), the next value yielded by the generator function is returned.

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

Either the function or the object may be called the "generator" depending on which Python source document you read. The Python glossary says generator functions, while the Python wiki implies generator objects. The Python tutorial remarkably manages to imply both usages in the space of three sentences:

根据所读取的Python源文档,可以将函数或对象称为“生成器”。Python术语表表示生成器函数,而Python wiki则表示生成器对象。Python教程成功地在三个句子的空间中包含了这两个用法:

Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the yield statement whenever they want to return data. Each time next() is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed).

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

The first two sentences identify generators with generator functions, while the third sentence identifies them with generator objects.

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

Despite all this confusion, one can seek out the Python language reference for the clear and final word:

尽管存在这些混乱,我们仍然可以查找Python语言的引用,以获得明确和最终的词汇:

The yield expression is only used when defining a generator function, and can only be used in the body of a function definition. Using a yield expression in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.

yield表达式仅用于定义生成器函数,只能用于函数定义的主体。在函数定义中使用yield表达式就足以使该定义创建生成器函数,而不是普通函数。

When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function.

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

So, in formal and precise usage, "generator" unqualified means generator object, not generator function.

因此,在正式和精确的用法中,“生成器”不限定是指生成器对象,而不是生成器函数。

The above references are for Python 2 but Python 3 language reference says the same thing. However, the Python 3 glossary states that

上面的引用是针对Python 2的,但是Python 3语言引用也是如此。但是,Python 3术语表说明了这一点

generator ... Usually refers to a generator function, but may refer to a generator iterator in some contexts. In cases where the intended meaning isn’t clear, using the full terms avoids ambiguity.

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

#5


4  

Generator Function, Generator Object, Generator:

发电机功能,发电机对象,发电机:

A Generator function is just like a regular function in Python but it contains one or more yield statements. Generator functions is a great tool to create Iterator objects as easy as possible. The Iterator object returend by generator function is also called Generator object or Generator.

生成器函数与Python中的常规函数类似,但它包含一个或多个yield语句。生成器函数是一个很好的工具,可以尽可能轻松地创建迭代器对象。由生成器函数返回的迭代器对象也称为生成器对象或生成器。

In this example I have created a Generator function which returns a Generator object <generator object fib at 0x01342480>. Just like other iterators, Generator objects can be used in a for loop or with the built-in function next() which returns the next value from generator.

在本例中,我创建了一个生成器函数,该函数在0x01342480>处返回生成器对象< Generator object fib。和其他迭代器一样,生成器对象可以用于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

So a generator function is the easiest way to create an Iterator object.

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

Iterator:

迭代器:

Every generator object is an iterator but not vice versa. A custom iterator object can be created if its class implements __iter__ and __next__ method (also called iterator protocol).

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

However, it is much easier to use generators function to create iterators because they simplify their creation, but a custom Iterator gives you more freedom and you can also implement other methods according to your requirements as shown in the below example.

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

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

#6


4  

Everybody has a really nice and verbose answer with examples and I really appreciate it. I just wanted to give a short few lines answer for people who are still not quite clear conceptually:

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

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

如果您创建自己的迭代器,这就有点麻烦了——您必须创建一个类,并至少实现iter和下一个方法。但是,如果您不想经历这些麻烦,并希望快速创建迭代器,那该怎么办呢?幸运的是,Python提供了定义迭代器的捷径。您所需要做的就是定义一个至少有一个调用的函数,现在当您调用该函数时,它将返回“something”,它会像一个迭代器一样(您可以调用next方法并在for循环中使用它)。这个东西在Python中有一个名为Generator的名称。

Hope that clarifies a bit.

希望能澄清一点。

#7


3  

You can compare both approaches for the same data:

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

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

Besides, if you check the memory footprint, the generator takes much less memory as it doesn't need to store all the values in memory at the same time.

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

#8


3  

Previous answers missed this addition: a generator has a close method, while typical iterators don’t. The close method triggers a StopIteration exception in the generator, which may be caught in a finally clause in that iterator, to get a chance to run some clean‑up. This abstraction makes it most usable in the large than simple iterators. One can close a generator as one could close a file, without having to bother about what’s underneath.

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

That said, my personal answer to the first question would be: iteratable has an __iter__ method only, typical iterators have a __next__ method only, generators has both an __iter__ and a __next__ and an additional close.

也就是说,我个人对第一个问题的回答是:iteratable只有__iter__方法,典型迭代器只有__next__方法,生成器有__iter__和__next__以及附加的结尾。

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.

对于第二个问题,我个人的回答是:在公共接口中,我倾向于使用生成器,因为它更有弹性:封闭方法具有更强的可组合性和收益率。在本地,我可能会使用迭代器,但前提是它是一个扁平的、简单的结构(迭代器不容易组合),而且如果有理由相信序列是相当短的,特别是当它在到达终点之前可能被停止时。我倾向于把迭代器看作一个低级的原语,除了文学性。

For control flow matters, generators are an as much important concept as promises: both are abstract and composable.

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

#1


395  

iterator is a more general concept: any object whose class has a next method (__next__ in Python 3) and an __iter__ method that does return self.

迭代器是一个更一般的概念:任何具有下一个方法(Python 3中的__next__)和一个返回self的__iter__方法的对象。

Every generator is an iterator, but not vice versa. A generator is built by calling a function that has one or more yield expressions (yield statements, in Python 2.5 and earlier), and is an object that meets the previous paragraph's definition of an iterator.

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

You may want to use a custom iterator, rather than a generator, when you need a class with somewhat complex state-maintaining behavior, or want to expose other methods besides next (and __iter__ and __init__). Most often, a generator (sometimes, for sufficiently simple needs, a generator expression) is sufficient, and it's simpler to code because state maintenance (within reasonable limits) is basically "done for you" by the frame getting suspended and resumed.

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

For example, a generator such as:

例如,生成器如:

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

generator = squares(a, b)

or the equivalent generator expression (genexp)

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

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

would take more code to build as a custom iterator:

需要更多的代码来作为定制迭代器构建:

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)

But, of course, with class Squares you could easily offer extra methods, i.e.

但是,当然,有了类平方,您可以很容易地提供额外的方法,例如。

    def current(self):
       return self.start

if you have any actual need for such extra functionality in your application.

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

#2


66  

What is the difference between iterators and generators? Some examples for when you would use each case would be helpful.

In summary: Iterators are objects that have an __iter__ and a __next__ (next in Python 2) method. Generators provide an easy, built-in way to create instances of Iterators.

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

A function with yield in it is still a function, that, when called, returns an instance of a generator object:

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

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

A generator expression also returns a generator:

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

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

For a more in-depth exposition and examples, keep reading.

要获得更深入的阐述和示例,请继续阅读。

A Generator is an Iterator

Specifically, generator is a subtype of iterator.

具体来说,generator是iterator的一种子类型。

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

We can create a generator several ways. A very common and simple way to do so is with a function.

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

Specifically, a function with yield in it is a function, that, when called, returns a generator:

具体地说,含有屈服的函数是一个函数,当调用它时,返回一个生成器:

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

And a generator, again, is an Iterator:

生成器也是迭代器:

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

An Iterator is an Iterable

An Iterator is an Iterable,

迭代器是可迭代的,

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

which requires an __iter__ method that returns an 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__

Some examples of iterables are tuples, lists, sets, dicts, strings, and range objects:

可以迭代的例子有元组、列表、集合、句柄、字符串和范围对象:

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

Iterators require a next or __next__ method

In Python 2:

在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

And in Python 3:

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

We can get the iterators from the builtin objects (or custom objects) with the iter function:

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

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

The __iter__ function is what is invoked when you attempt to use an object with a for-loop. Then __next__ or next is called on the iterator object to get each item out for the loop. The iterator raises StopIteration when you have exhausted it, and it cannot be reused at that point.

__iter__函数是在尝试使用带有for循环的对象时调用的函数。然后在iterator对象上调用__next__或next来获取循环的每个项。当您耗尽迭代时,迭代器将引发StopIteration,此时不能重用它。

From the docs:

From the Generator Types section of the Iterator Types section of the Built-in Types documentation:

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

Python’s generators provide a convenient way to implement the iterator protocol. If a container object’s __iter__() method is implemented as a generator, it will automatically return an iterator object (technically, a generator object) supplying the __iter__() and next() [__next__() in Python 3] methods. More information about generators can be found in the documentation for the yield expression.

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

(Emphasis added.)

(强调)。

So from this we learn that Generators are a (convenient) type of Iterator.

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

Example Iterator Objects

You might create object that implements the Iterator protocol by creating or extending your own object.

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

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

But it's easier to simply use a Generator to do this:

但是简单地使用一个生成器就可以做到这一点:

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

Or perhaps simpler, a Generator Expression (works similarly to list comprehensions):

或者更简单,一个生成器表达式(类似于列表理解的工作):

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

They can all be used in the same way:

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

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

Conclusion

You can use the Iterator protocol directly when you need to extend a Python object as an object that can be iterated over.

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

However, in the vast majority of cases, you are best suited to use yield to define a function that returns a Generator Iterator or consider Generator Expressions.

但是,在绝大多数情况下,您最适合使用yield来定义返回生成器迭代器或考虑生成器表达式的函数。

Finally, note that generators provide even more functionality as coroutines. I explain Generators, along with the yield statement, in depth on my answer to "What does the “yield” keyword do?".

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

#3


27  

Iterators:

迭代器:

Iterator are objects which uses next() method to get next value of sequence.

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

Generators:

发电机:

A generator is a function that produces or yields a sequence of values using yield method.

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

Every next() method call on generator object(for ex: f as in below example) returned by generator function(for ex: foo() function in below example), generates next value in sequence.

生成器函数(例:f)返回的每一个next()方法调用(例:foo()函数)都按顺序生成下一个值。

When a generator function is called, it returns an generator object without even beginning execution of the function. When next() method is called for the first time, the function starts executing until it reaches yield statement which returns the yielded value. The yield keeps track of i.e. remembers last execution. And second next() call continues from previous value.

当调用生成器函数时,它返回一个生成器对象,而不需要开始执行该函数。当第一次调用next()方法时,函数开始执行,直到到达yield语句,该语句返回yield值。收益率跟踪即记住最后一次执行。第二个next()调用从先前的值继续。

The following example demonstrates the interplay between yield and call to next method on generator object.

下面的例子演示了在生成器对象上的下一个方法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
>>>

#4


14  

Adding an answer because none of the existing answers specifically address the confusion in the official literature.

添加一个答案,因为现有的答案中没有一个明确地解决了官方文献中的困惑。

Generator functions are ordinary functions defined using yield instead of return. When called, a generator function returns a generator object, which is a kind of iterator - it has a next() method. When you call next(), the next value yielded by the generator function is returned.

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

Either the function or the object may be called the "generator" depending on which Python source document you read. The Python glossary says generator functions, while the Python wiki implies generator objects. The Python tutorial remarkably manages to imply both usages in the space of three sentences:

根据所读取的Python源文档,可以将函数或对象称为“生成器”。Python术语表表示生成器函数,而Python wiki则表示生成器对象。Python教程成功地在三个句子的空间中包含了这两个用法:

Generators are a simple and powerful tool for creating iterators. They are written like regular functions but use the yield statement whenever they want to return data. Each time next() is called on it, the generator resumes where it left off (it remembers all the data values and which statement was last executed).

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

The first two sentences identify generators with generator functions, while the third sentence identifies them with generator objects.

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

Despite all this confusion, one can seek out the Python language reference for the clear and final word:

尽管存在这些混乱,我们仍然可以查找Python语言的引用,以获得明确和最终的词汇:

The yield expression is only used when defining a generator function, and can only be used in the body of a function definition. Using a yield expression in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.

yield表达式仅用于定义生成器函数,只能用于函数定义的主体。在函数定义中使用yield表达式就足以使该定义创建生成器函数,而不是普通函数。

When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function.

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

So, in formal and precise usage, "generator" unqualified means generator object, not generator function.

因此,在正式和精确的用法中,“生成器”不限定是指生成器对象,而不是生成器函数。

The above references are for Python 2 but Python 3 language reference says the same thing. However, the Python 3 glossary states that

上面的引用是针对Python 2的,但是Python 3语言引用也是如此。但是,Python 3术语表说明了这一点

generator ... Usually refers to a generator function, but may refer to a generator iterator in some contexts. In cases where the intended meaning isn’t clear, using the full terms avoids ambiguity.

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

#5


4  

Generator Function, Generator Object, Generator:

发电机功能,发电机对象,发电机:

A Generator function is just like a regular function in Python but it contains one or more yield statements. Generator functions is a great tool to create Iterator objects as easy as possible. The Iterator object returend by generator function is also called Generator object or Generator.

生成器函数与Python中的常规函数类似,但它包含一个或多个yield语句。生成器函数是一个很好的工具,可以尽可能轻松地创建迭代器对象。由生成器函数返回的迭代器对象也称为生成器对象或生成器。

In this example I have created a Generator function which returns a Generator object <generator object fib at 0x01342480>. Just like other iterators, Generator objects can be used in a for loop or with the built-in function next() which returns the next value from generator.

在本例中,我创建了一个生成器函数,该函数在0x01342480>处返回生成器对象< Generator object fib。和其他迭代器一样,生成器对象可以用于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

So a generator function is the easiest way to create an Iterator object.

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

Iterator:

迭代器:

Every generator object is an iterator but not vice versa. A custom iterator object can be created if its class implements __iter__ and __next__ method (also called iterator protocol).

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

However, it is much easier to use generators function to create iterators because they simplify their creation, but a custom Iterator gives you more freedom and you can also implement other methods according to your requirements as shown in the below example.

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

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

#6


4  

Everybody has a really nice and verbose answer with examples and I really appreciate it. I just wanted to give a short few lines answer for people who are still not quite clear conceptually:

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

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

如果您创建自己的迭代器,这就有点麻烦了——您必须创建一个类,并至少实现iter和下一个方法。但是,如果您不想经历这些麻烦,并希望快速创建迭代器,那该怎么办呢?幸运的是,Python提供了定义迭代器的捷径。您所需要做的就是定义一个至少有一个调用的函数,现在当您调用该函数时,它将返回“something”,它会像一个迭代器一样(您可以调用next方法并在for循环中使用它)。这个东西在Python中有一个名为Generator的名称。

Hope that clarifies a bit.

希望能澄清一点。

#7


3  

You can compare both approaches for the same data:

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

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

Besides, if you check the memory footprint, the generator takes much less memory as it doesn't need to store all the values in memory at the same time.

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

#8


3  

Previous answers missed this addition: a generator has a close method, while typical iterators don’t. The close method triggers a StopIteration exception in the generator, which may be caught in a finally clause in that iterator, to get a chance to run some clean‑up. This abstraction makes it most usable in the large than simple iterators. One can close a generator as one could close a file, without having to bother about what’s underneath.

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

That said, my personal answer to the first question would be: iteratable has an __iter__ method only, typical iterators have a __next__ method only, generators has both an __iter__ and a __next__ and an additional close.

也就是说,我个人对第一个问题的回答是:iteratable只有__iter__方法,典型迭代器只有__next__方法,生成器有__iter__和__next__以及附加的结尾。

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.

对于第二个问题,我个人的回答是:在公共接口中,我倾向于使用生成器,因为它更有弹性:封闭方法具有更强的可组合性和收益率。在本地,我可能会使用迭代器,但前提是它是一个扁平的、简单的结构(迭代器不容易组合),而且如果有理由相信序列是相当短的,特别是当它在到达终点之前可能被停止时。我倾向于把迭代器看作一个低级的原语,除了文学性。

For control flow matters, generators are an as much important concept as promises: both are abstract and composable.

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