迭代器和生成器有什么区别? 有关何时使用每种情况的一些示例会有所帮助。
#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
来源:oschina
链接:https://my.oschina.net/stackoom/blog/3159941