在生成器函数上使用next()

8

我有这个生成器函数:

def gen():
    for i in range(3):
        yield i*i

现在当我在gen()上调用next()时,它每次都会给出第一个元素。
>>> next(gen())
0
>>> next(gen())
0

但是当我在for循环中使用它时,它按预期工作:

>>> for i in gen():
...     print(i)
... 
0
1
4

有人能解释一下这种效果的原因和我所缺失的概念吗?

3个回答

11

每次调用gen()函数,它都会返回一个新的生成器。

我认为最简单的理解方式是对比你正在做的事情:

>>> next(gen())
0
>>> next(gen())
0

使用以下方法:

>>> my_gen = gen()
>>> next(my_gen)
0
>>> next(my_gen)
1
>>> next(my_gen)
4
>>> next(my_gen)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

在这种情况下,我从同一个生成器中获取新的值。

你的函数每次调用gen()时都会返回一个新的生成器。那么,一个生成器函数直到初始化之前都不是生成器,为什么呢? - edam
1
@edam 想一想:如果生成器函数总是返回相同的生成器,那么它就不会很有用。如果你想创建一个新的生成器,你就必须编写一个新的函数。有关参考,请参阅文档:generator (function):"一个返回 generator iterator 的函数。" - wjandrea

5
每次调用该函数都会返回一个生成器对象。每次调用next()方法时,您将获得第一个项,即0*0,因为您不是在同一个对象上调用next()方法(每次都是新的对象)。但是在第二种情况下,您正在循环遍历一个生成器对象,并且它将继续消耗生成器,直到达到StopIteration。
为了更好地演示,您可以从生成器函数中创建两个迭代器对象,并同时循环遍历它们。
In [17]: g = gen()

In [18]: k = gen()

In [19]: for i, j in zip(g, k):
    ...:     print(i, j)
    ...:     
0 0
1 1
4 4

1
days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
def gen(d):
    for i in d: 
        yield i 

obj = gen(days)

print(next(obj, 'Default Value')) # 'Sun'
print(next(obj, 'Default Value')) # 'Mon'

print('--------------------------')    

for j in obj:
    print(j)  # 'Tue' 'Wed' 'Thu' 'Fri' 'Sat'

 
print(next(obj, 'Default Value')) # Default Value
  • 在上面,我们已经调用了next()两次,因此我们知道生成器函数保存程序执行状态,因此在for循环中它返回来自下一个生成器对象的对象。

  • 但是如果首先使用for循环,则在for循环期间,我们将接收或调用所有生成的对象,因此我们不会剩下任何生成器对象,因此我们将获得next()函数调用的默认值。

输出:

Sun
Mon
-------------------------
Tue
Wed
Thu
Fri
Sat
Default Value

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接