Python的“产量”行为

时间:2011-09-09 14:06:45

标签: python yield

我正在阅读python中的yield关键字,并尝试了解运行此示例:

def countfrom(n):
    while True:
        print "before yield"
        yield n
        n += 1
        print "after yield"

for i in countfrom(10):
    print "enter for loop"
    if i <= 20:
        print i
    else:
        break

输出结果为:

before yield
enter for loop
10
after yield
before yield
enter for loop
11
after yield
before yield
enter for loop
12
after yield
before yield
enter for loop
13
after yield
before yield
enter for loop
14
after yield
before yield
enter for loop
15
after yield
before yield
enter for loop
16
after yield
before yield
enter for loop
17
after yield
before yield
enter for loop
18
after yield
before yield
enter for loop
19
after yield
before yield
enter for loop
20
after yield
before yield
enter for loop

看起来yield将返回指定的值,并且将继续运行该函数直到结束(可能在并行线程中)。我的理解是否正确?

如果你能在不提及“发电机”的情况下回答这个问题,我会感激不尽,因为我试图一次理解一个。

6 个答案:

答案 0 :(得分:21)

您可以将其视为yield在遇到yield时简单“暂停”的功能。下次调用它时,它将在yield 保持其离开时的状态后恢复。

答案 1 :(得分:7)

不,只有一个线程。

for循环的每次迭代都会运行countFrom函数,直到它产生某些东西或返回。在yield之后,for循环的主体再次运行,然后,当一个新的迭代开始时,countFrom函数准确地从它停止的地方开始并再次运行直到它产生(或返回)。

您的示例的此修改版本将有助于更清楚地执行路径。

def countfrom(n):
    while n <= 12:
        print "before yield, n = ", n
        yield n
        n += 1
        print "after yield, n = ", n

for i in countfrom(10):
    print "enter for loop, i = ", i
    print i
    print "end of for loop iteration, i = ", i

<强>输出

before yield, n =  10
enter for loop, i =  10
10
end of for loop iteration, i =  10
after yield, n =  11
before yield, n =  11
enter for loop, i =  11
11
end of for loop iteration, i =  11
after yield, n =  12
before yield, n =  12
enter for loop, i =  12
12
end of for loop iteration, i =  12
after yield, n =  13

答案 2 :(得分:6)

..如果不提及生成器,你无法解释yield语句的含义;这就像试图解释什么是石头而不提岩石。即:yield语句是负责将正常函数转换为生成器的函数。

虽然您在此处找到了详细记录:http://docs.python.org/reference/simple_stmts.html#the-yield-statement

..对它的简要解释是:

  • 当调用使用yield语句的函数时,它返回一个“生成器迭代器”,具有.next()方法(可迭代对象的标准)
  • 每次调用生成器的.next()方法时(例如,通过使用for循环迭代对象),将调用该函数,直到遇到第一个yield。然后暂停函数执行并将值作为.next()方法的返回值传递。
  • 下次调用.next()时,函数执行将恢复到下一个yield等,直到函数返回。

这样做的一些好处是:

  • 内存使用量减少,因为内存只是为当前产生的值分配,而不是整个返回值列表(就像返回值列表一样)
  • “realtime”结果返回,因为它们的生成可以传递给调用者而无需等待生成结束(我用它来返回正在运行的进程的输出)

答案 3 :(得分:1)

函数countfrom不在并行线程中运行。这里发生的是每当for - 构造要求下一个值时,该函数将执行,直到它到达yield语句。当需要之后的下一个值时,该函数将从中断处继续执行。

虽然你要求不提及“发电机”,但它们与yield密切相关,因此单独谈论它并没有多大意义。您的countfrom函数实际返回的是“生成器对象”。它在调用后立即返回该对象,因此在某些事物(例如for - 循环)使用其方法.next()从生成器请求值之前,函数体不会被执行。

答案 4 :(得分:0)

yield语句存储您生成的值,直到再次调用该函数。 因此,如果您调用该函数(使用迭代器),它将再次运行该函数并为您提供值。 关键是它知道上次停在哪里

答案 5 :(得分:0)

Python运行直到它到达yield然后停止并冻结执行。它不会继续运行。它会在下一次调用countfrom

时“点击”

很容易说没有参考发电机但事实上产量和发电机是密不可分的。要真正理解它,你必须将它们视为同一主题。

通过以更加手动的方式使用您的示例中的生成器,很容易向我们展示我(以及其他人)所说的内容。

yield而不是return实际返回生成器的函数。然后,您可以通过调用next来使用该生成器。你很困惑,因为你的循环正在为你处理背景中的所有内容。

这是打开的内部结构:

def countfrom(n):
    while n <= 12:
        print "before yield, n = ", n
        yield n
        n += 1
        print "after yield, n = ", n


your_generator = countfrom(10)
next(your_generator)
print "see the after yield hasn't shown up yet, it's stopped at the first yield"
next(your_generator)
print "now it woke back up and printed the after... and continued through the loop until it got to back to yield"
next(your_generator)
print "rinse and repeate"