看看代码:
def main():
for p in test1(): print(p)
def test1():
s = set()
s.update(range(5))
for p in s: yield p
return s
为什么我只有0,1,2,3,4?输出应为:0,1,2,3,4两次(1表示'收益',1表示'收回')
PS:Python-3.4
答案 0 :(得分:3)
Python 3.3+生成器中的return语句不能按照您的想法执行。该值不会像普通函数一样返回给调用者,而是作为StopIteration
异常的属性添加,生成器会发出信号表示它已完成迭代。你在循环中看到的行为是无关的。
首先,让我们了解循环行为。这归结为一个简单的事实:当i
循环结束时,循环变量(例如for
)不会超出范围:
for i in range(5): # this loop will print 0 through 4
print(i)
print(i) # this line will print 4 again, since 4 it was the last value assigned to i
您的代码正是这样做的。您正在使用的else
子句没有什么特别之处,因为您永远不会break
退出循环。 (Neftas的答案解释了循环所附的else
是什么。)
至于return
值的去向,如果您手动迭代生成器,可以找到它:
gen = test1()
print(next(gen)) # prints 0
print(next(gen)) # prints 1
print(next(gen)) # prints 2
print(next(gen)) # prints 3
print(next(gen)) # prints 4
print(next(gen)) # prints set([0,1,2,3,4]) from the last yield statement
try:
next(gen)
except StopIteration as e:
print(e.value) # prints set([0,1,2,3,4]) from the return statement
这不是一种非常常见的用法。获取返回值的常用方法是在另一个生成器中使用yield from
表达式的结果:
def test3():
print(yield from test1())
这是一个生成与test1
完全相同的值的生成器,但它也会打印出test1
返回的值。
我不认为return
成语在大多数情况下非常有用。 yield from
在递归或其他复杂的生成器中非常有用,但我从未发现需要return
一个值。
如果您想了解有关yield from
表达式和生成器返回值的更多信息,请阅读PEP 380,其中介绍了Python 3.3中添加的新功能。
答案 1 :(得分:0)
有关生成器中return
的讨论,请参阅Blckknght的回答,这是关于else
循环中的for
子句。
如果您不喜欢nice article about else clauses in for loops,我会阅读documentation。
它的要点是else
循环中的for
子句完全是关于完成,而不是关于条件。比较:
if 1:
print "True"
else:
print "False"
这里,当比较结束时执行else
子句。
但是:
for i in xrange(5):
if i == 123:
print "Found it!"
break
else:
print "Value not in list"
# output: "Value not in list"
这里,else
子句被执行,除非执行流程命中break
语句:
for i in xrange(5):
if i == 4:
print "Found it!"
break
else:
print "Value not in list"
# output: "Found it!"
如果删除break
,则会打印两个字符串。在您的代码中,执行流程将始终到达else
语句,因此代码就会运行。