gpt4 book ai didi

python - 如何在嵌套函数中评估外部范围的变量?

转载 作者:太空宇宙 更新时间:2023-11-03 13:08:00 25 4
gpt4 key购买 nike

先上代码:

def another_func(func):
func()


def outer_func(pa=1, pb=2):
def inner_func():
print(pa)
print(type(inner_func))
another_func(inner_func)

if __name__ == '__main__':
outer_func()
#print "1"

我不确定,“inner_func”调用了“outer_func”的参数,但那是在“outer_func”的主体中。当 another_func 调用时,它如何“知道”有一个“pa”?

我的意思是,在“outer_func”中调用 another_func 时实际传递给的是什么?似乎不仅仅是函数对象的引用。

最佳答案

Python 中的函数对象不仅仅是函数,它们是 closures :1 他们携带对 def 所在的本地环境的引用。语句被执行。

特别是来自 outer_func 内部的局部变量可以从内部访问inner_func . (即使您是 return inner_func ,这些值也会保持事件状态,因此只要 inner_func 存在,闭包仍然有效。)

如果添加 nonlocal内声明inner_func ,它甚至可以从 outer_func 的主体中重新分配局部变量.

这是如何运作的?

好吧,一个def statement2 只是一个语句,就像其他任何语句一样。它的作用是这样的:

inner_func = _make_closure(<code from compiling inner_func body>, locals())

<code from compiling inner_func body>实际上是一个常量值——编译器将模块中每个函数的主体编译成常量 code位于 import 的对象时间。

但是从 _make_closure 返回的函数对象是一个动态创建的新事物,它引用了烘焙到其中的局部变量。每次运行 outer_func ,它会创建一个新的 inner_func同一个关闭 <code> ,每一个都捕获当前的本地环境。

细节稍微复杂一些——而且,在某种程度上,它们在实现之间有所不同,所以这将是特定于 CPython 的。

编译器的部分工作是找出函数中每个名称的变量类型。您可能已经阅读了有关全局变量与局部变量的规则(当且仅当您在函数体的某处对名称进行了赋值,并且没有 global 语句时,变量才是局部变量)。但是闭包使事情变得更加复杂。
  • 如果一个变量本来是本地的,但是一个嵌套函数引用了这个变量而不给它赋值,或者有一个 nonlocal语句,则它是外部函数中的单元格变量,内部函数中的自由变量。3
  • 当解释器调用一个函数时,它会创建一个 frame保存本地命名空间的对象——对所有函数局部变量的引用。
  • 但是单元格变量是特殊的:解释器创建一个特殊的 cell每个对象,并且对该单元格的引用进入命名空间,因此每次访问或更改值时都会在值前面有一个额外的取消引用。
  • 那是什么_make_closure上面的伪代码所做的是将单元格从外部函数的框架复制到嵌套函数上的一个特殊属性,称为 __closure__。 .
  • 然后,当您调用内部函数时,解释器会从 __closure__ 复制这些单元格。进入该功能的框架。
  • 因此,外部函数的框架和内部函数的框架都引用了相同的单元格,这就是它们可以共享变量的方式。

  • 更多关于此,请参阅 inspect 模块的文档,向您展示如何查找 __closure__ 之类的内容和 co_freevars在您的交互式解释器中,以及 dis 模块可让您查看函数编译成的实际字节码。

    1. 这是具有一系列相关但不同含义的词之一。 “闭包”可以表示在函数中捕获本地命名空间的技术,也可以表示已捕获的命名空间,也可以表示附加了已捕获命名空间的函数,也可以表示已捕获命名空间中的变量之一.通常从上下文中很明显你指的是哪一个。如果不是,您必须说“闭包捕获”或“闭包函数”或“闭包变量”之类的东西。

    2. 如果您想知道, lambda表达式的工作方式与 def 完全相同陈述。和 class定义不相同,但相似。

    3. 如果你有多层嵌套实际上会更复杂,但我们忽略它。

    关于python - 如何在嵌套函数中评估外部范围的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51550211/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com