Python中生成器的循环行为
我对不同的循环结构在使用简单生成器时表现得如此不同感到困惑。看看下面的代码:
example_list = [1, 2, 3, 4, 5]
for_count = 0
next_count = 0
while_count = 0
def consumer(iterable):
for item in iterable:
yield
return
for item in consumer(example_list):
print("For Count: {0}".format(for_count))
for_count += 1
# First while loop
while consumer(example_list).next():
print("Next Count: {0}".format(next_count))
next_count += 1
# Second while loop
while consumer(example_list):
print("While Count: {0}".format(while_count))
while_count += 1
if while_count > 10: # add contrived limit for infinite loop
break
这段代码的输出是:
对于计数: 0
对于计数: 1
对于计数: 2
对于计数: 3
对于计数: 4
当计数: 0
当计数: 1
当计数: 2
当计数: 3
当计数: 4
当计数: 5
当计数: 6
当计数: 7
当计数: 8
当计数: 9
当计数: 10
我希望能帮助我理解以下几点:
for
循环是怎么知道什么时候结束的,而第二个while
循环却不知道?我原本以为两个while
循环都会立即退出,因为None
被返回了。- 为什么使用
.next()
不会引发异常?consumer
这个例程并不是一个定义了__next__()
方法的类,所以当你使用yield
关键字时,它是怎么神奇地出现的? - 如果我把
consumer
改成yield item
,第一个while
循环为什么会变成像第二个那样无限循环? - 如果我把
consumer
改成简单地返回而不是返回任何东西,第二个while
循环会立即退出,而不是变成无限循环。我一直以为yield
本质上是一个可以恢复的return
。为什么它们在while
循环中被处理得如此不同?
2 个回答
只回答你问题的一部分:
你对 while
循环的误解在于,while
循环本身并不会像 for item in generator
循环那样去逐个处理生成器对象。
在你第二个 while
循环中,consumer(example_list)
总是返回一个生成器,这个生成器在布尔判断中被视为真(True),所以这个循环就会一直运行下去。
在第一个 while
循环中,你在测试这个生成器的第一个返回值,而这个值是 None
。因此,循环根本就不会开始。
关于 for
循环
你的第一个 for 循环运行得很正常。更新:Mark Ransomyield 后面没有跟上预期的 item
,所以它返回的是 [None, None, None, None, None]
,而不是 [1, 2, 3, 4, 5]
,不过它还是会遍历这个列表。
第一个 while
循环
同样的评论者0 被视为 False
。
第二个 while
循环
在第二个 while 循环中,你在测试 consumer(example_list)
的值。这里的 consumer(example_list)
是生成器对象本身,而不是它通过 next()
返回的值。这个对象本身永远不会等于 None 或其他 False
的等价物,所以你的循环永远不会结束。
你可以通过在循环中打印 consumer(example_list)
的值来看到这一点,这就是你的 while 条件:
>>> while_count=0
>>> while consumer(example_list):
... print while_count, consumer(example_list)
... while_count += 1
... if while_count > 10:
... break
输出为:
0 <generator object consumer at 0x1044a1b90>
1 <generator object consumer at 0x1044a1b90>
2 <generator object consumer at 0x1044a1b90>
3 <generator object consumer at 0x1044a1b90>
4 <generator object consumer at 0x1044a1b90>
5 <generator object consumer at 0x1044a1b90>
6 <generator object consumer at 0x1044a1b90>
7 <generator object consumer at 0x1044a1b90>
8 <generator object consumer at 0x1044a1b90>
9 <generator object consumer at 0x1044a1b90>
10 <generator object consumer at 0x1044a1b90>
第二个项目是这个对象,它永远不会等于 None
。