闭合不是为内部功能而形成的

时间:2018-06-12 15:06:20

标签: python python-3.x closures

这是一个带有本地函数的简单函数:

def raise_to(exp):
    def raise_to_exp(x, exp):
        return pow(x, exp)
    return raise_to_exp

现在我希望本地函数关闭exp,但不知道它不会。当我运行时:

square = raise_to(2)
print(square.__closure__)

我得到None。我错过了什么?

1 个答案:

答案 0 :(得分:4)

没有闭包,不,因为内部函数有自己的本地 exp变量;你用这个名字给了它一个参数。该参数掩盖了外部作用域中的名称,因此不会为其创建闭包。返回的函数需要两个参数,而raise_to()的参数只是被忽略:

>>> from inspect import signature
>>> def raise_to(exp):
...     def raise_to_exp(x, exp):
...         return pow(x, exp)
...     return raise_to_exp
...
>>> signature(raise_to(2))
<Signature (x, exp)>
>>> square = raise_to(2)
>>> square(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: raise_to_exp() missing 1 required positional argument: 'exp'
>>> square(5, 3)
125
>>> raise_to('This is ignored, really')(5, 3)
125

如果您希望从外部函数中取出exp参数,请从内部函数中删除:

def raise_to(exp):
    def raise_to_exp(x):
        return pow(x, exp)
    return raise_to_exp

现在exp是一个闭包:

>>> def raise_to(exp):
...     def raise_to_exp(x):
...         return pow(x, exp)
...     return raise_to_exp
...
>>> raise_to(2).__closure__
(<cell at 0x11041a978: int object at 0x10d908ae0>,)
>>> raise_to.__code__.co_cellvars
('exp',)

代码对象上的co_cellvars属性为您提供外部作用域中任何已关闭变量的名称。

返回的函数接受一个参数,现在实际使用raise_to()的参数:

>>> raise_to(2)(5)
25
>>> raise_to('Incorrect type for pow()')(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in raise_to_exp
TypeError: unsupported operand type(s) for ** or pow(): 'int' and 'str'