当你调用一个包含 yield 的函数时会发生什么?
What happens when you invoke a function that contains yield?
我阅读了here下面的例子:
>>> def double_inputs():
... while True: # Line 1
... x = yield # Line 2
... yield x * 2 # Line 3
...
>>> gen = double_inputs()
>>> next(gen) # Run up to the first yield
>>> gen.send(10) # goes into 'x' variable
如果我对上面的理解正确的话,这似乎意味着 Python 实际上在函数体中等待直到 next(gen)
到 "run up to" 到 Line 2
。换句话说,解释器 不会 开始执行函数体,直到我们调用 next
.
- 这真的正确吗?
- 据我所知,Python 不进行 AOT 编译,而且 "look ahead" 除了解析代码并确保其有效 Python 外,它的作用也不大。这个对吗?
- 如果以上是真的,Python 怎么会知道当我调用
double_inputs()
它需要等到我调用 next(gen)
才进入循环 while True
?
正确。调用 double_inputs
永远不会执行任何代码;它只是 returns 一个 generator
对象。 yield
表达式在正文中的存在,在 def
语句被 解析时发现 ,改变了 def
语句的语义以创建一个generator
对象而不是 function
对象。
函数包含 yield
是一个生成器。
当您调用 gen = double_inputs()
时,您会得到一个生成器实例作为结果。您需要通过调用 next
.
来使用此生成器
所以对于你的第一个问题,这是真的。当您第一次调用 next
.
时,它运行第 1、2、3 行
关于你的第二个问题,我不太明白你的意思。当你定义函数的时候,Python知道你在定义什么,运行它不需要向前看。
第三个问题,关键是yield
关键词。
Generator-function 是 de iure 函数,但 de facto 它是一个迭代器,即 class(实现了 __next__()
、__iter()__
和一些其他方法。)
换句话说,它是一个class 伪装成一个函数。
这意味着,“调用”这个函数实际上是创建这个class的实例,并解释了为什么“被调用函数”最初没有。这是您第 3 个 个问题的答案。
您第 1st 个问题的答案令人惊讶 没有。
实例总是等待调用它的方法,__next__()
方法(通过调用next()
内置函数间接启动)不是生成器的唯一方法。其他方法是 .send()
,您可以使用 gen.send(None)
而不是 next(gen)
。
您的第 2 个 个问题的答案是否。 Python 解释器绝不是“向前看”,没有例外,包括你的
... except for parsing the code and making sure it's valid Python.
或者这个问题的答案是是,如果你的意思是“解析只直到下一个命令”。 ;-)
我阅读了here下面的例子:
>>> def double_inputs():
... while True: # Line 1
... x = yield # Line 2
... yield x * 2 # Line 3
...
>>> gen = double_inputs()
>>> next(gen) # Run up to the first yield
>>> gen.send(10) # goes into 'x' variable
如果我对上面的理解正确的话,这似乎意味着 Python 实际上在函数体中等待直到 next(gen)
到 "run up to" 到 Line 2
。换句话说,解释器 不会 开始执行函数体,直到我们调用 next
.
- 这真的正确吗?
- 据我所知,Python 不进行 AOT 编译,而且 "look ahead" 除了解析代码并确保其有效 Python 外,它的作用也不大。这个对吗?
- 如果以上是真的,Python 怎么会知道当我调用
double_inputs()
它需要等到我调用next(gen)
才进入循环while True
?
正确。调用 double_inputs
永远不会执行任何代码;它只是 returns 一个 generator
对象。 yield
表达式在正文中的存在,在 def
语句被 解析时发现 ,改变了 def
语句的语义以创建一个generator
对象而不是 function
对象。
函数包含 yield
是一个生成器。
当您调用 gen = double_inputs()
时,您会得到一个生成器实例作为结果。您需要通过调用 next
.
所以对于你的第一个问题,这是真的。当您第一次调用 next
.
关于你的第二个问题,我不太明白你的意思。当你定义函数的时候,Python知道你在定义什么,运行它不需要向前看。
第三个问题,关键是yield
关键词。
Generator-function 是 de iure 函数,但 de facto 它是一个迭代器,即 class(实现了 __next__()
、__iter()__
和一些其他方法。)
换句话说,它是一个class 伪装成一个函数。
这意味着,“调用”这个函数实际上是创建这个class的实例,并解释了为什么“被调用函数”最初没有。这是您第 3 个 个问题的答案。
您第 1st 个问题的答案令人惊讶 没有。
实例总是等待调用它的方法,__next__()
方法(通过调用next()
内置函数间接启动)不是生成器的唯一方法。其他方法是 .send()
,您可以使用 gen.send(None)
而不是 next(gen)
。
您的第 2 个 个问题的答案是否。 Python 解释器绝不是“向前看”,没有例外,包括你的
... except for parsing the code and making sure it's valid Python.
或者这个问题的答案是是,如果你的意思是“解析只直到下一个命令”。 ;-)