在构建参数化的装饰器时,我没有意识到在Python中不允许在嵌套功能中通过参数中通过的重新分配。进一步,我意识到这也是简单功能也是如此。我将演示置于以下嵌套函数:
def a(s):
def b():
def c():
# nonlocal s # fix
print(s)
# while s:
# s -= 1 # uncommenting raises UnboundLocalError
print(s)
return None
return c()
return b()
a(3)
# 3
# 3
我希望通过添加注释的while
循环来获得以下所需的输出:
a(3)
# 3
# 0
接下来,删除while
循环的两行会产生以下错误,这表明将值重新分配到s
会引起错误:
<ipython-input-37-7141eb599936> in c()
3 def c():
4 # nonlocal s # fix
----> 5 print(s)
6 while s:
7 s -= 1 # uncommenting raises UnboundLocalError
UnboundLocalError: local variable 's' referenced before assignment
最后,Uncompomenting nonlocal
解决了此问题,并按照本文建议提供所需的输出。
尽管解决了问题,但我想了解问题的根源。我注意到追溯指出了参数化参数s
(例如print(s)
(的首次使用,而不是指向实际导致错误的行(即while
循环/分配(。
我怀疑在调用功能后,Python首先建立了本地范围的作业。然后,分配从外部范围内获得更高的优先级或覆盖的遗传变量。因此,如果没有对s
分配,则使用了外部s
。相比之下,通过分配,s
在函数调用中重新定义,并且在初始分配之前的任何引用都会引起错误。这是正确的,还是有人可以解释Python实际在做什么?
如果一个函数包含对变量的分配(包括诸如 -=
之类的增强作业,则变量自动局部,除非明确声明为 global
(或 nonlocal
(。它是自动全局的,而无需任何声明(因为当它没有值的源头时,它几乎不可能是本地变量(。此分析是在生成任何代码之前执行的,因此您会得到这样的情况,其中随后的代码行中的情况可能导致较早的行变成错误。