迭代器和生成器之间的区别是什么?举一些例子来说明你在什么时候使用每种情况会很有帮助。
当前回答
无代码4行小抄:
A generator function is a function with yield in it.
A generator expression is like a list comprehension. It uses "()" vs "[]"
A generator object (often called 'a generator') is returned by both above.
A generator is also a subtype of iterator.
其他回答
这篇文章涵盖了两者之间的许多细节差异,但想在两者之间的概念差异上添加一些东西:
[…GoF书中定义的迭代器从集合中检索项,而生成器可以“凭空”生成项。这就是为什么斐波那契序列生成器是一个常见的例子:无限级数的数字不能存储在一个集合中。
Ramalho,卢西亚诺。流利的Python(第415页)。O ' reilly媒体。Kindle版。
当然,它并没有涵盖所有的方面,但我认为它给出了一个很好的概念,当一个人是有用的。
迭代器和生成器之间的区别是什么?举一些例子来说明你在什么时候使用每种情况会很有帮助。
总结:迭代器是具有__iter__和__next__ (Python 2中的next)方法的对象。生成器提供了一种简单的内置方法来创建iterator实例。
包含yield的函数仍然是一个函数,当调用它时,返回一个生成器对象的实例:
def a_function():
"when called, returns generator object"
yield
生成器表达式也返回一个生成器:
a_generator = (i for i in range(0))
有关更深入的阐述和示例,请继续阅读。
Generator是一个迭代器
具体来说,generator是迭代器的子类型。
>>> 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__
一些可迭代对象的例子是内置元组、列表、字典、集合、冻结集、字符串、字节字符串、字节数组、范围和memoryview:
>>> 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() [__next__() in python3]方法。关于生成器的更多信息可以在yield表达式的文档中找到。
(强调)。
从这里我们了解到generator是一种(方便的)迭代器类型。
迭代器对象示例
您可以通过创建或扩展自己的对象来创建实现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 Iterator的函数或考虑Generator expression。
最后,请注意生成器作为协程提供了更多的功能。我在回答“yield”关键字做什么?”时,深入地解释了Generators和yield语句。
可迭代对象是可以(自然地)迭代的对象。然而,要做到这一点,你将需要一个类似迭代器对象的东西,是的,术语可能令人困惑。可迭代对象包括__iter__方法,该方法将返回可迭代对象的迭代器对象。
迭代器对象是一个实现迭代器协议的对象——一组规则。在这种情况下,它必须至少有这两个方法:__iter__和__next__。__next__方法是一个提供新值的函数。__iter__方法返回迭代器对象。在更复杂的对象中,可能有单独的迭代器,但在更简单的情况下,__iter__返回对象本身(通常返回self)。
一个iterable对象是一个列表对象。它不是一个迭代器,但它有一个__iter__方法,返回一个迭代器。你可以直接以things.__iter__()的形式调用这个方法,或者使用iter(things)。
如果你想遍历任何集合,你需要使用它的迭代器:
things_iterator = iter(things)
for i in things_iterator:
print(i)
然而,Python会自动使用迭代器,这就是为什么你从来没有看到上面的例子。相反,你可以这样写:
for i in things:
print(i)
自己编写迭代器可能很乏味,所以Python有一个更简单的选择:生成器函数。生成器函数不是普通的函数。不是遍历代码并返回最终结果,而是延迟代码,函数立即返回一个生成器对象。
生成器对象类似于迭代器对象,因为它实现了迭代器协议。这对于大多数目的来说已经足够好了。在其他答案中有许多生成器的例子。
简而言之,迭代器是一个对象,它允许您迭代另一个对象,无论它是一个集合还是其他一些值的来源。生成器是一个简化的迭代器,它或多或少完成相同的工作,但更容易实现。
通常情况下,如果你只需要发电机,你会选择发电机。但是,如果您正在构建一个更复杂的对象,其中包含其他特性之间的迭代,则应该使用迭代器协议。
iterator是一个更通用的概念:任何具有__next__方法(Python 2中的next)和__iter__方法且返回self的对象。
每个生成器都是迭代器,反之亦然。生成器是通过调用具有一个或多个yield表达式(yield语句,在Python 2.5及更早版本中)的函数来构建的,它是一个满足上一段对迭代器定义的对象。
当你需要一个具有复杂状态维护行为的类,或者想公开__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 2
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
如果您的应用程序中确实需要这些额外的功能。
生成器函数,生成器对象,生成器:
Generator函数就像Python中的常规函数一样,但它包含一个或多个yield语句。Generator函数是一个很好的工具,可以尽可能简单地创建Iterator对象。generator函数返回的Iterator对象也称为generator对象或generator。
在这个例子中,我创建了一个Generator函数,它返回一个Generator对象< Generator对象fib at 0x01342480>。就像其他迭代器一样,Generator对象可以在for循环中使用,也可以与从Generator返回下一个值的内置函数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
因此,生成器函数是创建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
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用pip3安装包时,“Python中的ssl模块不可用”
- 无法切换Python与pyenv
- Python if not == vs if !=
- 如何从scikit-learn决策树中提取决策规则?
- 为什么在Mac OS X v10.9 (Mavericks)的终端中apt-get功能不起作用?
- 将旋转的xtick标签与各自的xtick对齐
- 为什么元组可以包含可变项?
- 如何合并字典的字典?
- 如何创建类属性?
- 不区分大小写的“in”
- 在Python中获取迭代器中的元素个数
- 解析日期字符串并更改格式
- 使用try和。Python中的if
- 如何在Python中获得所有直接子目录