迭代器和生成器之间的区别是什么?举一些例子来说明你在什么时候使用每种情况会很有帮助。
当前回答
强烈推荐Ned Batchelder的迭代器和生成器示例
一个没有生成器的方法,它对偶数进行处理
def evens(stream):
them = []
for n in stream:
if n % 2 == 0:
them.append(n)
return them
而通过使用发电机
def evens(stream):
for n in stream:
if n % 2 == 0:
yield n
我们不需要任何列表或返回语句 有效的大/无限长的流…它只是走动并产生值
调用evens方法(生成器)和往常一样
num = [...]
for n in evens(num):
do_smth(n)
发电机也用于打破双环
迭代器
满页的书是可迭代对象,书签是可迭代对象 迭代器
而这个书签除了下一步移动什么也做不了
litr = iter([1,2,3])
next(litr) ## 1
next(litr) ## 2
next(litr) ## 3
next(litr) ## StopIteration (Exception) as we got end of the iterator
使用生成器…我们需要一个函数
使用迭代器…我们需要next和iter
如前所述:
Generator函数返回一个迭代器对象
Iterator的全部好处:
每次在内存中存储一个元素
其他回答
可迭代对象是可以(自然地)迭代的对象。然而,要做到这一点,你将需要一个类似迭代器对象的东西,是的,术语可能令人困惑。可迭代对象包括__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有一个更简单的选择:生成器函数。生成器函数不是普通的函数。不是遍历代码并返回最终结果,而是延迟代码,函数立即返回一个生成器对象。
生成器对象类似于迭代器对象,因为它实现了迭代器协议。这对于大多数目的来说已经足够好了。在其他答案中有许多生成器的例子。
简而言之,迭代器是一个对象,它允许您迭代另一个对象,无论它是一个集合还是其他一些值的来源。生成器是一个简化的迭代器,它或多或少完成相同的工作,但更容易实现。
通常情况下,如果你只需要发电机,你会选择发电机。但是,如果您正在构建一个更复杂的对象,其中包含其他特性之间的迭代,则应该使用迭代器协议。
我用一种非常简单的方式专门为Python新手编写,尽管Python在本质上做了很多事情。
让我们从最基本的开始:
考虑一个列表,
l = [1,2,3]
让我们写一个等效函数:
def f():
return [1,2,3]
打印(l)的O /p: [1,2,3] & O /p打印(f()): [1,2,3]
让列表l可迭代:在python中,列表总是可迭代的,这意味着你可以在任何你想要的时候应用迭代器。
让我们在list上应用迭代器:
iter_l = iter(l) # iterator applied explicitly
让我们把一个函数设为可迭代的,也就是说,写一个等效的生成器函数。 在python中,只要你引入关键字yield;它变成了一个生成器函数,迭代器将隐式应用。
注意:每个生成器在应用隐式迭代器时总是可迭代的,这里隐式迭代器是关键 因此生成器函数将是:
def f():
yield 1
yield 2
yield 3
iter_f = f() # which is iter(f) as iterator is already applied implicitly
如果你观察到,一旦你让函数f成为一个生成器,它就已经是iter(f)
Now,
L是列表,在应用迭代器方法iter后,它变成, iter(左) F已经是iter(F),在应用迭代器方法“iter”它 变成iter(iter(f))也就是iter(f)
这有点像你将int类型转换为int(x)它已经是int类型并且它将保持int(x)
例如o/p:
print(type(iter(iter(l))))
is
<class 'list_iterator'>
别忘了这是Python而不是C或c++
因此,由上述解释得出的结论是:
列出l ~= iter(l) 生成函数f == iter(f)
生成器函数,生成器对象,生成器:
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
强烈推荐Ned Batchelder的迭代器和生成器示例
一个没有生成器的方法,它对偶数进行处理
def evens(stream):
them = []
for n in stream:
if n % 2 == 0:
them.append(n)
return them
而通过使用发电机
def evens(stream):
for n in stream:
if n % 2 == 0:
yield n
我们不需要任何列表或返回语句 有效的大/无限长的流…它只是走动并产生值
调用evens方法(生成器)和往常一样
num = [...]
for n in evens(num):
do_smth(n)
发电机也用于打破双环
迭代器
满页的书是可迭代对象,书签是可迭代对象 迭代器
而这个书签除了下一步移动什么也做不了
litr = iter([1,2,3])
next(litr) ## 1
next(litr) ## 2
next(litr) ## 3
next(litr) ## StopIteration (Exception) as we got end of the iterator
使用生成器…我们需要一个函数
使用迭代器…我们需要next和iter
如前所述:
Generator函数返回一个迭代器对象
Iterator的全部好处:
每次在内存中存储一个元素
添加一个答案,因为现有的答案都没有专门解决官方文献中的困惑。
生成器函数是用yield而不是return定义的普通函数。当被调用时,生成器函数返回一个生成器对象,这是一种迭代器——它有一个next()方法。当调用next()时,将返回生成器函数产生的下一个值。
函数或对象都可以被称为“生成器”,这取决于你阅读的Python源文档。Python术语表表示生成器函数,而Python wiki表示生成器对象。Python教程成功地在三句话中暗示了这两种用法:
生成器是用于创建迭代器的简单而强大的工具。它们像常规函数一样编写,但在需要返回数据时使用yield语句。每次在它上调用next()时,生成器都会从停止的地方恢复(它会记住所有的数据值和最后执行的语句)。
前两句话用生成器函数标识生成器,而第三句话用生成器对象标识它们。
尽管存在这些困惑,但人们可以从Python语言参考中找到明确的最终答案:
yield表达式仅在定义生成器函数时使用,并且只能在函数定义的主体中使用。在函数定义中使用yield表达式足以导致该定义创建一个生成器函数,而不是普通函数。 当调用generator函数时,它返回一个称为generator的迭代器。然后,该生成器控制生成器函数的执行。
因此,在正式和精确的用法中,“generator”不合格指的是生成器对象,而不是生成器功能。
上面的参考资料是针对Python 2的,但Python 3语言参考资料也说了同样的事情。然而,Python 3术语表指出
发电机……通常指生成器函数,但在某些上下文中也可能指生成器迭代器。在意图不明确的情况下,使用完整的术语可以避免歧义。
推荐文章
- 证书验证失败:无法获得本地颁发者证书
- 当使用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中获得所有直接子目录