Python的“屈服”行为

2024-04-27 16:03:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在阅读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将返回指定的值,并将继续运行函数直到结束(可能在并行线程中)。我的理解正确吗?

如果你能不提“发电机”来回答这个问题,我会很感激,因为我一次只能理解一个发电机。


Tags: inlooptrue示例fordef关键字发电机
3条回答

不,只有一根线。

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

…如果不提到生成器,就无法解释yield语句的含义;这就像试图解释什么是石头而不提到石头一样。也就是说:yield语句负责将正常函数转换为生成器。

当你发现它在这里有很好的记录:http://docs.python.org/reference/simple_stmts.html#the-yield-statement

……它的简要解释是:

  • 当使用yield语句的函数被调用时,它返回一个“生成器迭代器”,它有一个.next()方法(iterable对象的标准)
  • 每次调用生成器的.next()方法(例如,使用for循环迭代对象)时,都会调用函数,直到遇到第一个yield。然后暂停函数执行,并传递一个值作为.next()方法的返回值。
  • 下一次调用.next()时,函数将继续执行,直到下一次yield等,直到函数返回某些内容。

这样做的一些好处是:

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

你可以把它想象成当遇到yield时,yield的函数只是“暂停”。下次调用它时,它将在yield保持离开时的状态后恢复。

相关问题 更多 >