使用检查模块显示在堆栈框架中的未绑定名称
Unbound name showing up in stack frame using inspect module
我最近 运行 遇到了一个很难追踪的错误。我不小心将 class 名称重新用作变量(请参阅下面的代码),因此当我尝试调用 class 时,我(可以理解)得到了一个错误。很难追踪的原因是我的调试器 (Wing IDE 5.1.10) 会在调试探针中成功执行该行,但是当我尝试 运行 解释器中的同一行时它出错了。在进一步调查中,我发现当我使用检查模块检查帧数据时,名称仍然显示为绑定到我的 class 的全局变量。因此,我对在我的框架中明确定义和绑定的名称收到 UnboundLocalError 感到困惑。
这重现了问题:
import inspect
class MyClass(object):
def __init__(self):
print "MyClass init() method called successfully"
def newscope():
#MyClass is not in the current frame's locals:
assert 'MyClass' not in inspect.currentframe().f_locals.keys()
#MyClass is in the current frame's globals and can be called successfully:
class_object = inspect.currentframe().f_globals['MyClass']
print class_object
class_object()
#But, calling MyClass by name results in UnboundLocalError: local
#variable 'MyClass' referenced before assignment:
print MyClass
#Strangely, if at this point I go into the debug probe and run the same
#line (print MyClass) it executes successfully, printing
#"<class '__main__.MyClass'>"
#Re-assigning the name MyClass is what causes the UnboundLocalError:
MyClass = 5
if __name__ == '__main__':
newscope()
结果:
<class '__main__.MyClass'>
MyClass init() method called successfully
Traceback (most recent call last):
Python Shell, prompt 1, line 29
Python Shell, prompt 1, line 19
UnboundLocalError: local variable 'MyClass' referenced before assignment
再次,我明白为什么我会收到 UnboundLocalError。我不明白的是,为什么 inspect 模块仍将名称显示为绑定到 class 对象,而显然情况并非如此。我是不是遗漏了什么,或者这是 inspect 模块中的错误?
我 运行宁 python 2.7.11.
首先,关于例外情况,我认为您的 IDE 不符合 python 规范:
A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block.
[...]
If a name is bound in a block, it is a local variable of that block.
If a name is bound at the module level, it is a global variable. (The
variables of the module code block are local and global.) If a
variable is used in a code block but not defined there, it is a free
variable.
[...]
When a name is not found at all, a NameError exception is raised. If
the name refers to a local variable that has not been bound, a
UnboundLocalError exception is raised. UnboundLocalError is a subclass
of NameError.
https://docs.python.org/2.7/reference/executionmodel.html#naming-and-binding
因此,我知道整个块都被解析了,它找到了你的变量,并被添加到本地范围,但在赋值之前,它被认为是一个 自由变量
编辑
关于inspect
,我认为它列出了本地名称空间中的绑定变量,因此,您看不到您的变量。这很合乎逻辑:如果键 'MyClass' 尚未绑定,您会给它什么值?
实际上,您应该使用 inspect.currentframe().f_code.co_varnames
来获得您想要的 ;)
import inspect
from pprint import pprint
class MyClass(object):
def __init__(self):
print("MyClass init() method called successfully")
def newscope():
pprint(inspect.currentframe().f_code.co_varnames)
print("----------")
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
try:
pprint(MyClass)
except Exception as e:
print(e)
MyClass = 5
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
if __name__ == '__main__':
newscope()
你得到:
('MyClass', 'e')
----------
{}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f2fa3901160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7f2fa39b8f28>,
'pprint': <function pprint at 0x7f2fa1fe66a8>}
----------
local variable 'MyClass' referenced before assignment
{'MyClass': 5}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f2fa3901160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7f2fa39b8f28>,
'pprint': <function pprint at 0x7f2fa1fe66a8>}
----------
删除你的变量
import inspect
from pprint import pprint
class MyClass(object):
def __init__(self):
print("MyClass init() method called successfully")
def newscope():
pprint(inspect.currentframe().f_code.co_varnames)
print("----------")
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
try:
pprint(MyClass)
except Exception as e:
print(e)
# MyClass = 5
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
if __name__ == '__main__':
newscope()
你得到:
('e',)
----------
{}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fc6d3fcb160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7fc6d4082f28>,
'pprint': <function pprint at 0x7fc6d26b06a8>}
----------
<class '__main__.MyClass'>
{}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fc6d3fcb160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7fc6d4082f28>,
'pprint': <function pprint at 0x7fc6d26b06a8>}
----------
如果一个值被分配给函数内的变量,该变量将成为该函数内的局部变量。
从创建函数的那一刻起,即在第一次调用之前,该变量就被视为局部变量。 Python 实际上优化了对局部变量的访问并且不查找 locals() 字典,但是 "knows" 确切地找到每个局部变量的位置(参见 this answer about performance within a function)。
所以,这个赋值是在函数的末尾完成这一事实并没有什么不同。在你的函数 newscope
中,变量 MyClass
是一个局部变量。使用后分配给 MyClass
变量实际上是导致此示例中的 UnboundLocalError
的原因。
举个更简单的例子:
a = 4
def global_a_example():
print a # a is a global variable: prints 4
def local_a_example():
a = 5
print a # a is a local variable: prints 5
def unbound_local_a_example():
print a # a is a local variable, but not initialized: raises UnboundLocalError
a = 5
编辑: 解释为什么看起来变量已绑定
请注意,未绑定的局部变量不会出现在局部变量字典中。那不是因为他们不是本地人。这是因为它们不受约束。请参阅以下示例:
a = 1
b = 2
def f():
assert 'a' in globals() # of course
assert 'a' not in locals() # local 'a' has not been initialized and has no value
assert 'a' in f.__code__.co_varnames # 'a' is local nevertheless!
assert 'b' not in f.__code__.co_varnames # 'b' is not local...
# a != 1 test would raise and exception here because 'a' is local and uninitialized
a = 10 # initialize local 'a' (and store it in locals)
assert 'a' in globals() # it is still in globals, yes
assert 'a' in locals() # it is also in locals
assert globals()['a'] == 1 # global 'a' has value 1
assert locals()['a'] == 2 # local 'a' has value 2
assert a == 10 # a is local 'a'!
assert b == 2 # b is global 'b'
# but you don't even have to call f()!!!
# 'a' is already defined to be a local variable in f, see:
print f.__code__.co_varnames # prints ('a',)
因此,'a' 在写入之前不会绑定。它是 globals dict 中的关键,但这无关紧要。它没有从那个字典中使用,因为它被定义为本地的。
我最近 运行 遇到了一个很难追踪的错误。我不小心将 class 名称重新用作变量(请参阅下面的代码),因此当我尝试调用 class 时,我(可以理解)得到了一个错误。很难追踪的原因是我的调试器 (Wing IDE 5.1.10) 会在调试探针中成功执行该行,但是当我尝试 运行 解释器中的同一行时它出错了。在进一步调查中,我发现当我使用检查模块检查帧数据时,名称仍然显示为绑定到我的 class 的全局变量。因此,我对在我的框架中明确定义和绑定的名称收到 UnboundLocalError 感到困惑。
这重现了问题:
import inspect
class MyClass(object):
def __init__(self):
print "MyClass init() method called successfully"
def newscope():
#MyClass is not in the current frame's locals:
assert 'MyClass' not in inspect.currentframe().f_locals.keys()
#MyClass is in the current frame's globals and can be called successfully:
class_object = inspect.currentframe().f_globals['MyClass']
print class_object
class_object()
#But, calling MyClass by name results in UnboundLocalError: local
#variable 'MyClass' referenced before assignment:
print MyClass
#Strangely, if at this point I go into the debug probe and run the same
#line (print MyClass) it executes successfully, printing
#"<class '__main__.MyClass'>"
#Re-assigning the name MyClass is what causes the UnboundLocalError:
MyClass = 5
if __name__ == '__main__':
newscope()
结果:
<class '__main__.MyClass'>
MyClass init() method called successfully
Traceback (most recent call last):
Python Shell, prompt 1, line 29
Python Shell, prompt 1, line 19
UnboundLocalError: local variable 'MyClass' referenced before assignment
再次,我明白为什么我会收到 UnboundLocalError。我不明白的是,为什么 inspect 模块仍将名称显示为绑定到 class 对象,而显然情况并非如此。我是不是遗漏了什么,或者这是 inspect 模块中的错误?
我 运行宁 python 2.7.11.
首先,关于例外情况,我认为您的 IDE 不符合 python 规范:
A scope defines the visibility of a name within a block. If a local variable is defined in a block, its scope includes that block.
[...]
If a name is bound in a block, it is a local variable of that block. If a name is bound at the module level, it is a global variable. (The variables of the module code block are local and global.) If a variable is used in a code block but not defined there, it is a free variable.
[...]
When a name is not found at all, a NameError exception is raised. If the name refers to a local variable that has not been bound, a UnboundLocalError exception is raised. UnboundLocalError is a subclass of NameError.
https://docs.python.org/2.7/reference/executionmodel.html#naming-and-binding
因此,我知道整个块都被解析了,它找到了你的变量,并被添加到本地范围,但在赋值之前,它被认为是一个 自由变量
编辑
关于inspect
,我认为它列出了本地名称空间中的绑定变量,因此,您看不到您的变量。这很合乎逻辑:如果键 'MyClass' 尚未绑定,您会给它什么值?
实际上,您应该使用 inspect.currentframe().f_code.co_varnames
来获得您想要的 ;)
import inspect
from pprint import pprint
class MyClass(object):
def __init__(self):
print("MyClass init() method called successfully")
def newscope():
pprint(inspect.currentframe().f_code.co_varnames)
print("----------")
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
try:
pprint(MyClass)
except Exception as e:
print(e)
MyClass = 5
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
if __name__ == '__main__':
newscope()
你得到:
('MyClass', 'e')
----------
{}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f2fa3901160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7f2fa39b8f28>,
'pprint': <function pprint at 0x7f2fa1fe66a8>}
----------
local variable 'MyClass' referenced before assignment
{'MyClass': 5}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f2fa3901160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7f2fa39b8f28>,
'pprint': <function pprint at 0x7f2fa1fe66a8>}
----------
删除你的变量
import inspect
from pprint import pprint
class MyClass(object):
def __init__(self):
print("MyClass init() method called successfully")
def newscope():
pprint(inspect.currentframe().f_code.co_varnames)
print("----------")
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
try:
pprint(MyClass)
except Exception as e:
print(e)
# MyClass = 5
pprint(inspect.currentframe().f_locals)
print("----------")
pprint(inspect.currentframe().f_globals)
print("----------")
if __name__ == '__main__':
newscope()
你得到:
('e',)
----------
{}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fc6d3fcb160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7fc6d4082f28>,
'pprint': <function pprint at 0x7fc6d26b06a8>}
----------
<class '__main__.MyClass'>
{}
----------
{'MyClass': <class '__main__.MyClass'>,
'__builtins__': <module 'builtins' (built-in)>,
'__cached__': None,
'__doc__': None,
'__file__': 'test.py',
'__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fc6d3fcb160>,
'__name__': '__main__',
'__package__': None,
'__spec__': None,
'inspect': <module 'inspect' from '/usr/lib/python3.5/inspect.py'>,
'newscope': <function newscope at 0x7fc6d4082f28>,
'pprint': <function pprint at 0x7fc6d26b06a8>}
----------
如果一个值被分配给函数内的变量,该变量将成为该函数内的局部变量。
从创建函数的那一刻起,即在第一次调用之前,该变量就被视为局部变量。 Python 实际上优化了对局部变量的访问并且不查找 locals() 字典,但是 "knows" 确切地找到每个局部变量的位置(参见 this answer about performance within a function)。
所以,这个赋值是在函数的末尾完成这一事实并没有什么不同。在你的函数 newscope
中,变量 MyClass
是一个局部变量。使用后分配给 MyClass
变量实际上是导致此示例中的 UnboundLocalError
的原因。
举个更简单的例子:
a = 4
def global_a_example():
print a # a is a global variable: prints 4
def local_a_example():
a = 5
print a # a is a local variable: prints 5
def unbound_local_a_example():
print a # a is a local variable, but not initialized: raises UnboundLocalError
a = 5
编辑: 解释为什么看起来变量已绑定
请注意,未绑定的局部变量不会出现在局部变量字典中。那不是因为他们不是本地人。这是因为它们不受约束。请参阅以下示例:
a = 1
b = 2
def f():
assert 'a' in globals() # of course
assert 'a' not in locals() # local 'a' has not been initialized and has no value
assert 'a' in f.__code__.co_varnames # 'a' is local nevertheless!
assert 'b' not in f.__code__.co_varnames # 'b' is not local...
# a != 1 test would raise and exception here because 'a' is local and uninitialized
a = 10 # initialize local 'a' (and store it in locals)
assert 'a' in globals() # it is still in globals, yes
assert 'a' in locals() # it is also in locals
assert globals()['a'] == 1 # global 'a' has value 1
assert locals()['a'] == 2 # local 'a' has value 2
assert a == 10 # a is local 'a'!
assert b == 2 # b is global 'b'
# but you don't even have to call f()!!!
# 'a' is already defined to be a local variable in f, see:
print f.__code__.co_varnames # prints ('a',)
因此,'a' 在写入之前不会绑定。它是 globals dict 中的关键,但这无关紧要。它没有从那个字典中使用,因为它被定义为本地的。