我想知道如何访问另一个函数内的函数.我看到这样的代码:
>>> def make_adder(x):
def adder(y):
return x+y
return adder
>>> a = make_adder(5)
>>> a(10)
15
Run Code Online (Sandbox Code Playgroud)
那么,还有另一种方法来调用adder 函数吗?我的第二个问题是为什么在最后一行我adder不打电话adder(...)?
很好的解释非常感谢.
Mar*_*ers 18
你真的不想走下这个兔子洞,但如果你坚持,那就有可能.有一些工作.
每次调用时都会重新创建嵌套函数make_adder():
>>> import dis
>>> dis.dis(make_adder)
2 0 LOAD_CLOSURE 0 (x)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object adder at 0x10fc988b0, file "<stdin>", line 2>)
9 MAKE_CLOSURE 0
12 STORE_FAST 1 (adder)
4 15 LOAD_FAST 1 (adder)
18 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
MAKE_CLOSURE那里的操作码创建了一个带闭包的函数,一个x从父函数引用的嵌套函数(LOAD_CLOSURE操作码为函数构建闭包单元).
在不调用make_adder函数的情况下,您只能访问代码对象; 它与make_adder()函数代码一起存储为常量.但是,字节代码adder可以将x变量作为范围单元格访问,这使得代码对象几乎对您无用:
>>> make_adder.__code__.co_consts
(None, <code object adder at 0x10fc988b0, file "<stdin>", line 2>)
>>> dis.dis(make_adder.__code__.co_consts[1])
3 0 LOAD_DEREF 0 (x)
3 LOAD_FAST 0 (y)
6 BINARY_ADD
7 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
LOAD_DEREF从闭包单元格加载值.要使代码对象再次成为函数对象,您必须将其传递给函数构造函数:
>>> from types import FunctionType
>>> FunctionType(make_adder.__code__.co_consts[1], globals(),
... None, None, (5,))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: arg 5 (closure) expected cell, found int
Run Code Online (Sandbox Code Playgroud)
但正如您所看到的,构造函数希望找到一个闭包,而不是一个整数值.要创建一个闭包,我们需要一个具有自由变量的函数; 编译器标记为可用于结束的那些.并且它需要将那些已关闭的值返回给我们,否则无法创建闭包.因此,我们创建一个嵌套函数只是为了创建一个闭包:
def make_closure_cell(val):
def nested():
return val
return nested.__closure__[0]
cell = make_closure_cell(5)
Run Code Online (Sandbox Code Playgroud)
现在我们可以adder()不用调用重新创建make_adder:
>>> adder = FunctionType(make_adder.__code__.co_consts[1], globals(),
... None, None, (cell,))
>>> adder(10)
15
Run Code Online (Sandbox Code Playgroud)
也许只是打电话make_adder()会更简单.
顺便提一下,正如您所看到的,函数是Python中的第一类对象.make_adder是一个对象,并通过添加(somearguments)您调用,或调用该函数.在这种情况下,该函数返回另一个函数对象,您也可以调用它.在上面如何创建adder()没有调用的曲折例子中make_adder(),我make_adder没有调用它就引用了函数对象; 例如,反汇编附加到它的Python字节代码,或从中检索常量或闭包.同样,make_adder()函数返回adder函数对象; 该点的make_adder()是创建别的东西以后调用它的功能.
上面的会话考虑了Python 2和3之间的兼容性.较旧的Python 2版本的工作方式相同,尽管有些细节略有不同; 某些属性具有不同的名称,例如func_code代替__code__.如果您想了解详细信息,请在inspect模块和Python数据模型中查找有关这些内容的文档.
不,你不能直接调用它,因为它是一个局部变量make_adder.
您需要使用adder()因为return adder在调用adder时返回了函数对象make_adder(5).要执行此功能对象,您需要()
def make_adder(x):
def adder(y):
return x+y
return adder
...
>>> make_adder(5) #returns the function object adder
<function adder at 0x9fefa74>
Run Code Online (Sandbox Code Playgroud)
在这里你可以直接调用它,因为你可以访问它,因为它是由函数返回的make_adder.返回的对象实际上称为闭包,因为即使函数make_addr已经返回,adder它返回的函数对象仍然可以访问该变量x.在py3.x中,您还可以修改xusing nonlocal语句的值.
>>> make_adder(5)(10)
15
Run Code Online (Sandbox Code Playgroud)
Py3.x示例:
>>> def make_addr(x):
def adder(y):
nonlocal x
x += 1
return x+y
return adder
...
>>> f = make_addr(5)
>>> f(5) #with each call x gets incremented
11
>>> f(5)
12
#g gets it's own closure, it is not related to f anyhow. i.e each call to
# make_addr returns a new closure.
>>> g = make_addr(5)
>>> g(5)
11
>>> g(6)
13
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3908 次 |
| 最近记录: |