【问题标题】:What happens when you invoke a function that contains yield?当你调用一个包含 yield 的函数时会发生什么?
【发布时间】:2020-08-22 01:45:16
【问题描述】:
我看了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) 在函数体中“运行”到 Line 2。换句话说,在我们调用 next 之前,解释器不会开始执行函数体。
- 这真的正确吗?
- 据我所知,Python 不进行 AOT 编译,并且除了解析代码并确保它是有效的 Python 之外,它并没有“向前看”太多。它是否正确?
- 如果上述情况属实,当我调用
double_inputs() 时,Python 怎么知道它需要等到我调用next(gen) 才能进入循环while True?
【问题讨论】:
标签:
python
python-3.x
generator
abstract-syntax-tree
yield
【解决方案1】:
正确。调用double_inputs 永远不会执行任何代码;它只是返回一个generator 对象。当def 语句被解析时发现,主体中yield 表达式的存在改变了def 语句的语义以创建generator 对象而不是@987654327 @对象。
【解决方案2】:
函数包含yield是一个生成器。
当您调用gen = double_inputs() 时,您会得到一个生成器实例作为结果。你需要调用next来使用这个生成器。
所以对于你的第一个问题,这是真的。当您第一次调用 next 时,它会运行第 1、2、3 行。
关于你的第二个问题,我不太明白你的意思。当你定义函数时,Python 就知道你在定义什么,运行它时不需要往前看。
对于第三个问题,关键是yield 关键字。
【解决方案3】:
Generator-function de iure是一个函数,但de facto它是一个迭代器,即一个class(已实现__next__() ,__iter()__,以及其他一些方法。)
换句话说,它是一个类伪装成一个函数。
这意味着,“调用”这个函数实际上是创建这个类的一个实例,并解释了为什么“被调用的函数”最初什么都不做。这是您第三个rd问题的答案。
您的第一个st问题的答案令人惊讶地否。
实例总是等待调用它的方法,__next__() 方法(通过调用next() 内置函数间接启动)不是生成器的唯一方法。其他方法是.send(),您可以使用gen.send(None) 代替您的next(gen)。
您的第二个nd 问题的答案是否。 Python 解释器绝不是“向前看”,没有例外,包括你的
...除了解析代码并确保它是有效的 Python。
或者这个问题的答案是是,如果你的意思是“解析只到下一个命令”。 ;-)