文档章节

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

 技术盛宴
发布于 01/19 11:14
字数 2812
阅读 60
收藏 0

迭代器和生成器有什么区别? 有关何时使用每种情况的一些示例会有所帮助。


#1楼

迭代器:

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

发电机:

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

生成器函数(如以下示例中的ex: foo()函数)返回的生成器对象(如以下示例中的ex: f next()上的每个next()方法调用,都会按顺序生成下一个值。

调用生成器函数时,它甚至不开始执行该函数就返回生成器对象。 首次调用next()方法时,该函数开始执行直到到达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()
>>> 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
>>>

#2楼

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): # __next__ in Python 3
       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

如果您在应用程序中实际需要这种额外功能。


#3楼

迭代器和生成器有什么区别? 有关何时使用每种情况的一些示例会有所帮助。

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

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

这需要一个返回迭代器的__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(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
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(), frozenset(), '', b'', bytearray(), range(0), memoryview(b'')))
True

当您尝试将对象与for循环一起使用时,将调用__iter__方法。 然后,在迭代器对象上调用__next__方法以使每个项目都进入循环。 耗尽后,迭代器将引发StopIteration ,并且此时无法重用。

从文档中

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

Python的生成器提供了一种实现迭代器协议的便捷方法。 如果将容器对象的__iter__()方法实现为生成器,它将自动返回提供__iter__()next() [Python 3]方法中的__next__()的迭代器对象(从技术上讲,是生成器对象)。 有关生成器的更多信息,可以在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, 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表达式的函数。

最后,请注意,生成器提供了更多的协同程序功能。 我将在我对“ yield”关键字有什么作用?”的回答中深入解释Generators以及yield语句。


#4楼

添加答案是因为现有答案中没有一个专门解决官方文献中的混乱。

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

函数或对象都可以称为“生成器”,具体取决于您阅读的是哪个Python源文档。 Python词汇表显示生成器函数,而Python Wiki隐含生成器对象。 Python教程显着地设法在两个句子之间暗示了这两种用法:

生成器是用于创建迭代器的简单而强大的工具。 它们的编写方式与常规函数类似,但是只要要返回数据就使用yield语句。 每次在其上调用next()时,生成器都会从上次中断的地方继续(它会记住所有数据值以及最后执行的语句)。

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

尽管存在所有这些困惑,但您仍然可以找到Python语言参考来获得清晰明确的词:

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

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

因此,在正式和精确的用法中, “生成器”不合格表示生成器对象,而不是生成器功能。

上面的参考是针对Python 2的,但是Python 3语言参考却说了同样的话。 但是, Python 3词汇表指出

generator ...通常指生成器函数,但在某些情况下可能指代生成器迭代器。 在预期含义不明确的情况下,使用完整术语可以避免歧义。


#5楼

生成器功能,生成器对象,生成器:

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

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

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

本文转载自:https://stackoom.com/question/BeNZ/Python的生成器和迭代器之间的区别

粉丝 0
博文 1611
码字总数 0
作品 0
深圳
高级程序员
私信 提问
加载中

评论(0)

Python第六章-函数05-迭代器&生成器

python作为一个既面向对象,又支持函数式编程的语言,函数的使用方面有很多特点。 比如:闭包,装饰器,迭代器等 函数的高级应用 容器:生活中常见的容器有哪些?袋子,盆子,水杯,书包,铅...

平仄平仄平平仄
04/02
0
0
Python 生成器和迭代器,yield语句

什么是迭代器 顾名思义,迭代器就是用于迭代操作(for 循环)的对象,它像列表一样可以迭代获取其中的每一个元素,任何实现了 next 方法 (python2 是 next)的对象都可以称为迭代器。 它与列...

stardsd
01/01
0
0
更深入的理解 Python 中的迭代

深入探讨 Python 的 循环来看看它们在底层如何工作,以及为什么它们会按照它们的方式工作。 Python 的 循环不会像其他语言中的 循环那样工作。在这篇文章中,我们将深入探讨 Python 的 循环来...

01%
2018/05/26
0
0
玩转可迭代对象迭代器生成器 - 知乎

在Python中,经常可以看到可迭代对象、迭代器、生成器,如何得到一个可迭代对象,如何把它变成迭代器,如何得到生成器,它们到底有什么区别和联系呢? 简单来说,它们的关系如下图 从概念上来...

Python头条
03/13
0
0
对中知识点的总结和扩展

对中知识点的总结和扩展 《Effective Python》一书结合Python的语言特性,对代码规范进行了详细总结,是一本非常不错的Python实操指南。但我在阅读的过程中发现有些地方仅仅是告知读者“怎么...

果然多弗朗
04/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Dynamic Wallpaper for Mac(精美的动态壁纸) v3.5

Dynamic Wallpaper for Mac是一款功能强大的动态壁纸应用。动态壁纸应用 Mac版为你提供200+精美视频素材,卡通动漫、自然人文、萌宠萌物、游戏世界、创意视频、古风古色等等。 Dynamic Wall...

云不若
20分钟前
15
0
Android手机直播之差网络处理和发送

今天为大家介绍Andriod手机直播流程中的差网络处理和发送过程,图玩智能为企业提供直播定制开发,搭建更加完善的直播系统,欢迎随时咨询www.toivan.com. 差网络处理 好的网络下视音频能够得到...

图玩智能科技
22分钟前
18
0
广州哪里可以开发票-广州本地网

电薇13564998196陈晨幵票百分百保真-可先开验。从主业来看,2019年众诚保险围绕车险业务采取增设分支机构、加强合作、优化用户体验等动作,但综合成本率仍有所上行,业内指出,车险的价格透明...

嘌徴fp2090
27分钟前
18
0
深圳哪里可以开发票-深圳本地网

电薇13564998196陈晨幵票百分百保真-可先开验。从主业来看,2019年众诚保险围绕车险业务采取增设分支机构、加强合作、优化用户体验等动作,但综合成本率仍有所上行,业内指出,车险的价格透明...

訮票徴fp2090
28分钟前
26
0
北京哪里可以开发票-北京本地网

电/薇13564998196百分百保真、从主业来看,2019年众诚保险围绕车险业务采取增设分支机构、加强合作、优化用户体验等动作,但综合成本率仍有所上行,业内指出,车险的价格透明度属天然属性,利...

訮票嶶fp2090
29分钟前
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部