内部函数没有形成闭包

4

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

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个回答

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'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接