生成器的Python循环行为

时间:2014-08-27 18:49:26

标签: python loops return generator yield

我很困惑为什么不同的循环结构在与简单生成器一起使用时表现得如此不同。请考虑以下代码:

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

我很感激帮助理解以下内容:

  1. for循环如何知道何时结束但不知道第二个while循环?我预计两个while循环会在None产生后立即退出。
  2. 为什么不使用.next()引发异常? consumer例程不是定义了__next__()方法的类,因此当您使用yield关键字时,它会神奇地出现吗?
  3. 为什么如果我将consumer更改为yield item,第一个while循环会变得像第二个循环一样无限?
  4. 如果我将consumer改为简单地返回而不是产生任何东西,则第二个while循环立即退出而不是变为无限。我的印象是yield基本上是return,您可以从中恢复。为什么while循环对它们的处理方式不同?

2 个答案:

答案 0 :(得分:6)

for循环

您的第一个for循环按预期工作。 更新Mark Ransom注意到您的yield未附带预期的item,因此只返回[None, None, None, None, None]而不是[1, 2, 3, 4, 5] - 但它仍然遍历列表。

第一个while循环

The very same commentator也注意到第一个while循环永远不会启动,因为0False - 在Python中等效。

第二个while循环

在第二个while循环中,您正在测试consumer(example_list)的值。这是生成器对象本身,而不是由next()返回的值。对象本身永远不等于None或任何其他False等价物 - 所以你的循环永远不会结束。

通过在循环中打印{while}条件consumer(example_list)的值可以看出这一点:

>>> 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

答案 1 :(得分:1)

仅回答您问题的一部分:

您对while循环的误解是,while循环不会像for item in generator循环一样迭代生成器对象。

第二个while循环中的consumer(example_list)总是返回一个生成器,它的计算结果为布尔值True,因此循环会永远运行。

在第一个while循环中,您正在测试该生成器的第一个yield值,即None。因此,循环甚至没有开始。