我正在使用python 2.7,但是试图创建一个代码来检查对象是否是与python 3+兼容的basetring的子类。我试图遵循suggested here方法,并在流程中发现了一个我不理解的行为
如果我这样做:
def foo():
try: basestring
except NameError:
print "a"
foo()
没有任何反应。
如果我在except:
里面略微修改了那段代码def foo():
try: basestring
except NameError:
print "a"
basestring=str
foo()
然后打印“a”。
我不明白如何向except块添加内容,可能会影响异常的触发。
我在函数外检查了相同的代码:
try:
basestring
except NameError:
print("a")
basestring=str
但在这种情况下没有打印出来。
答案 0 :(得分:5)
当你向函数添加basestring = str
时,你告诉python应该将basestring
视为局部变量。但是,在执行第一个语句时, 没有名为basestring
的局部变量(只有全局),因此python引发UnboundLocalError
。
由于UnboundLocalError
继承自NameError
,您的异常处理会被触发,您会看到a
已打印出来。
如果你对这个细节很感兴趣 - 我们可以使用dis
将其分开:
import dis
def foo():
try:
basestring
except NameError:
print("a")
basestring=str
def bar():
try:
basestring
except NameError:
print("a")
dis.dis(foo)
print('--' * 20)
dis.dis(bar)
请注意,对于foo
,使用basestring
操作码检索LOAD_FAST
(这意味着它正在寻找本地变量)。但是,在bar
中,使用basestring
操作码检索LOAD_GLOBAL
。
答案 1 :(得分:3)
在第一种情况下,很容易,basestring
上已解析名称__builtins__.basestring
。 try块没有引发异常,因此行为应该符合预期。
在第二种情况下,这很棘手。在函数内使用名称basestring
使该名称成为函数的局部变量。 请注意,函数本地的名称是在函数定义时确定的。执行函数的第一行时,Python已经知道名称basestring
是函数的局部变量。
>>> def foo():
... basestring
... potato
... errorerrorerror
...
>>> print foo.func_code.co_names
('basestring', 'potato', 'errorerrorerror')
>>> print foo.func_code.co_varnames
()
在foo()
行调用NameError
potato
。与下面的bar()
进行比较和对比,NameError
就行了basestring
:
>>> def bar():
... basestring
... potato
... errorerrorerror
... basestring = "D'Addario EXL160 Medium"
...
>>> print bar.func_code.co_names
('potato', 'errorerrorerror')
>>> print bar.func_code.co_varnames
('basestring',)
因此,引发的异常是由于在绑定到对象之前使用了名称,这在Python中是一个错误。这是运行时的错误,而不是定义时的错误。第三种情况与第一种情况类似 - “局部变量”的概念不适用于全球范围。