Python的行为&x27;s";“收益率”;
我正在阅读python中的Python的行为&x27;s";“收益率”;,python,yield,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 e
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
看起来yield将返回指定的值,并将继续运行函数直到结束(可能是在并行线程中)。我的理解正确吗
如果您能回答这个问题而不提及“生成器”,我将不胜感激,因为我试图一次理解一个生成器。yield语句存储您生成的值,直到再次调用该函数为止。 因此,如果您(使用迭代器)调用该函数,它将再次运行该函数并给出值。
关键是它知道上次在哪里中断了你可以把它想象成当遇到屈服的函数时,它只是“暂停”。下次调用它时,它将在
yield
后恢复,保持它离开时的状态 没有,只有一个线程
for循环的每次迭代都会运行countFrom
函数,直到它产生某个结果或返回。在产生之后,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
函数
countfrom
不是在并行线程中运行的。这里发生的事情是,每当for
-construct请求下一个值时,函数将执行,直到它到达yield
语句。当需要之后的下一个值时,函数将从其停止的位置继续执行
虽然您要求不要提及“生成器”,但它们与
收益率
有着密切的联系,因此单独谈论它们是没有意义的。您的countfrom
函数实际返回的是一个“生成器对象”。它在调用该对象后立即返回该对象,因此函数体根本不会执行,直到有东西(例如for
-loop)使用其方法.next()
从生成器请求值。如果不提及生成器,就无法解释yield
语句的含义;这就像试图解释什么是石头而不提及岩石。也就是说:yield语句负责将正常函数转换为生成器
虽然您发现这里有很好的文档记录:
…其简要说明如下:
- 调用使用yield语句的函数时,它返回一个“生成器迭代器”,具有
方法(iterable对象的标准).next()
- 每次调用生成器的
方法时(例如,通过使用for循环迭代对象),都会调用函数,直到遇到第一个成品。然后暂停函数执行,并传递一个值作为.next()
方法的返回值.next()
- 下次调用
时,函数将继续执行,直到下一次.next()
,等等,直到函数返回某些内容产生
- 更少的内存使用,因为内存只分配给当前生成的值,而不是整个返回值列表(就像返回值列表一样)
- “实时”结果返回,因为它们是生成的,可以在不等待生成结束的情况下传递给调用方(我用它来返回正在运行的进程的输出)
屈服
,然后停止并冻结执行。它不会继续运行。在下一次调用countfrom
在不提及发电机的情况下,很容易说这一点,但事实是,产量和发电机是密不可分的。要真正理解它,你必须将它们视为同一个主题
通过以更手动的方式使用示例中的生成器,很容易向自己证明我(和其他人)所说的是正确的
一个函数,yield
s而不是return
ing真正返回一个生成器。然后,您可以通过调用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"
def countfrom(n):
现在,我想我明白了,yield
就像一个return
,它将在下次调用时从yield
行继续运行?不,但它会知道上次“n”的值是多少。在本例中,它似乎无关紧要,因为您可以将n作为一个参数传递,但稍后它会变得非常有用。我想我误解了您的评论。您的想法是正确的(对不起),看起来这里的生成器有点混乱(我也花了一些时间才完全理解它们):状态不是在多次调用函数之间保持的,而是在调用返回的生成器对象的.next()方法之间保持的。当然,这是通过对其返回值进行迭代来完成的。因此,收益率的工作方式类似于返回
,它将从该行继续,在下次调用时保留该值?不,您不需要再次调用函数来恢复,您必须调用next()返回的生成器对象上的
方法。@redShadow但是在我的示例中没有调用next()
,那么它是如何恢复的呢?@Tom Brito,next()
是由for
循环在引擎盖下执行的。也就是说,“iterable”对象只是一个具有next()
方法的对象,该方法应为其包含的每个项返回一个值,并在最后一个项被删除时引发异常reached@Tom:解释下一步
需要使用您没有使用的单词
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
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"