考虑以下代码:
def main():
print('Calling methodA()')
methodA()
print('Calling methodB(True)')
methodB(True)
print('Calling methodB(False)')
try:
methodB(False)
except UnboundLocalError as error:
print(f'--> "UnboundLocalError" raised: {error}')
def methodA():
print('Running methodA()')
print('"method_original" in globals(): ' + str('method_original' in globals()))
method_original()
def methodB(patch_function):
print(f'Running methodB({patch_function})')
print('"method_original" in globals(): ' + str('method_original' in globals()))
if patch_function:
method_original=method_patched
method_original()
def method_original():
print('Running method_original()')
def method_patched():
print('Running method_patched()')
if __name__ == '__main__':
main()
输出如下:
Calling methodA()
Running methodA()
"method_original" in globals(): True
Running method_original()
Calling methodB(True)
Running methodB(True)
"method_original" in globals(): True
Running method_patched()
Calling methodA(False)
Running methodB(False)
"method_original" in globals(): True
--> "UnboundLocalError" raised: local variable 'method_original' referenced before assignment
这没有意义,因为"method_original"在globals()中。这个错误可以简单地在methodB()
的开头添加global method_original
来修复,但是在某些情况下,我们有很多函数,把它们都放在每个方法的开头可能是一件很痛苦的事情。
有什么规则可以避免这种行为吗?
//BR !
让我用一个更简单的例子来解释:
def fn(a):
if a % 2 == 0:
x = a
return x
print(fn(10)) # Fine
print(fn(9)) # UnboundLocalError: local variable 'x' referenced before assignment
在编译时,当解释器到达函数时,它看到有对x
的赋值,因此将x
标记为&;local&;;变量。然后在"运行时间"中解释器试图只在本地命名空间中找到它!另一方面,只有当a
是偶数时才定义x
。
如果它出现在全局命名空间中并不重要,现在我想在我的示例中添加一个名为x
的全局变量:
def fn(a):
if a % 2 == 0:
x = a
return x
x = 50
print(fn(10)) # Fine
print(fn(9)) # UnboundLocalError: local variable 'x' referenced before assignment
并没有什么改变。解释器仍然试图在中找到x
本地命名空间中的函数。
同样的事情发生在你的例子中。
显示哪些变量是"local"
def fn(a):
if a % 2 == 0:
x = a
return x
print(fn.__code__.co_varnames)
co_varnames
是包含局部变量名的元组(从参数名开始)
解决方案:
要么使用global
(我看到你不喜欢),或者不要在函数内进行赋值,例如将methodB
更改为:
def methodB(patch_function):
print(f'Running methodB({patch_function})')
print('"method_original" in globals(): ' + str('method_original' in globals()))
if patch_function:
method_patched()
else:
method_original()