函数参数语义(嵌套函数)
Function parameter semantics (with nested functions)
我正在学习 python,但我正在努力了解 Python 如何处理闭包。我通常理解这是一个自由变量,它存储在内存中,在被调用者作用域过期后很长时间内可以访问。我很困惑这种设置是如何解决的。
def do_something(x):
return lambda y: y + x;
f = do_something(4);
f(4)
这里的 f(4) 似乎使用了 lambda 函数签名而不是 do_something 签名。
它 returns 8,但内部是什么导致 python 使用 y 而不是 x 作为输入参数?我是否应该将 do_something
视为类似于 class 的定义,其中 f = do_something(4)
是构造函数而 f(4)
是要采取的实际操作?
请参阅 this 了解我第一次遇到此问题的地方。
表达式lambda y: y + x
创建了一个新函数,这个函数由do_something
返回给它的调用者。在这个函数中,x
是一个自由变量,闭包将参数的引用保存到用于创建它的 do_something
函数中。所以当你打电话给
f = do_something(4)
相当于:
f = lambda y: y + 4
相当于:
def f(y):
return y + 4
然后当您调用 f(4)
时,它会调用该函数,将 y
绑定到 f
参数。
你是对的,这类似于 class 构造函数的工作方式;在某些编程语言中,闭包被用作 class 个实例的内部实现。 类 添加诸如继承之类的内容,并且通常还提供更简单的语法来声明 class 属性和方法。
函数对象有一个属性,可以将值存储在 "cell" 中。您可以从 __closure__
属性访问封闭变量:
>>> def do_something(x):
... return lambda y: y + x;
...
>>> f = do_something(4)
>>> f.__closure__[0]
<cell at 0x105d86600: int object at 0x7f905ac12bd0>
这似乎没什么用。幸运的是,获取单元格的内容也很容易:
>>> f.__closure__[0].cell_contents
4
好的,这只是谜题的第一部分(python 如何存储闭包数据)。让我们看看 f
的反汇编字节码,看看 python 对这些数据做了什么:
>>> import dis
>>> dis.dis(f)
2 0 LOAD_FAST 0 (y)
3 LOAD_DEREF 0 (x)
6 BINARY_ADD
7 RETURN_VALUE
第一个代码 LOAD_FAST
用于加载局部变量(在 C 中存储为指向对象的指针数组 -- 0
表示这是第一个对象大批)。在这种情况下 y
是一个局部变量,因为它在函数的签名中。下一个代码是 [LOAD_DEREF
](enter link description here),它实际上在单元格中查找并从闭包中加载值。这在低层次上完成了这个问题的图片......
在更高的层次上,你不需要担心这些。您只需要知道 python 函数能够查找包含它的任何范围的值。
我正在学习 python,但我正在努力了解 Python 如何处理闭包。我通常理解这是一个自由变量,它存储在内存中,在被调用者作用域过期后很长时间内可以访问。我很困惑这种设置是如何解决的。
def do_something(x):
return lambda y: y + x;
f = do_something(4);
f(4)
这里的 f(4) 似乎使用了 lambda 函数签名而不是 do_something 签名。
它 returns 8,但内部是什么导致 python 使用 y 而不是 x 作为输入参数?我是否应该将 do_something
视为类似于 class 的定义,其中 f = do_something(4)
是构造函数而 f(4)
是要采取的实际操作?
请参阅 this 了解我第一次遇到此问题的地方。
表达式lambda y: y + x
创建了一个新函数,这个函数由do_something
返回给它的调用者。在这个函数中,x
是一个自由变量,闭包将参数的引用保存到用于创建它的 do_something
函数中。所以当你打电话给
f = do_something(4)
相当于:
f = lambda y: y + 4
相当于:
def f(y):
return y + 4
然后当您调用 f(4)
时,它会调用该函数,将 y
绑定到 f
参数。
你是对的,这类似于 class 构造函数的工作方式;在某些编程语言中,闭包被用作 class 个实例的内部实现。 类 添加诸如继承之类的内容,并且通常还提供更简单的语法来声明 class 属性和方法。
函数对象有一个属性,可以将值存储在 "cell" 中。您可以从 __closure__
属性访问封闭变量:
>>> def do_something(x):
... return lambda y: y + x;
...
>>> f = do_something(4)
>>> f.__closure__[0]
<cell at 0x105d86600: int object at 0x7f905ac12bd0>
这似乎没什么用。幸运的是,获取单元格的内容也很容易:
>>> f.__closure__[0].cell_contents
4
好的,这只是谜题的第一部分(python 如何存储闭包数据)。让我们看看 f
的反汇编字节码,看看 python 对这些数据做了什么:
>>> import dis
>>> dis.dis(f)
2 0 LOAD_FAST 0 (y)
3 LOAD_DEREF 0 (x)
6 BINARY_ADD
7 RETURN_VALUE
第一个代码 LOAD_FAST
用于加载局部变量(在 C 中存储为指向对象的指针数组 -- 0
表示这是第一个对象大批)。在这种情况下 y
是一个局部变量,因为它在函数的签名中。下一个代码是 [LOAD_DEREF
](enter link description here),它实际上在单元格中查找并从闭包中加载值。这在低层次上完成了这个问题的图片......
在更高的层次上,你不需要担心这些。您只需要知道 python 函数能够查找包含它的任何范围的值。