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