2016-11-15 108 views
2

我正在使用python 2.7,但试图做一个代码来检查一个对象是否是与python 3+兼容的basestring的子类。我试图采取的办法suggested here并在此过程中发现一个行为,我不明白异常处理中这种奇怪的行为是什么?

如果我做的:

def foo(): 
    try: basestring 
    except NameError: 
     print "a" 
foo() 

没有任何反应。

如果我稍微修改刚内除了代码:

def foo(): 
    try: basestring 
    except NameError: 
     print "a" 
     basestring=str 
foo() 

然后 “a” 被打印。

我不明白如何在except块中添加某些东西会影响异常的触发。

我查了相同的代码的功能外:

try: 
    basestring 
except NameError: 
    print("a") 
    basestring=str 

,但没有被印刷在这种情况下。

回答

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错误之前使用。这是运行时的错误,而不是定义时的错误。第三种情况与第一种情况类似 - “局部变量”的概念不适用于全局范围。 “

+1

”**请注意,函数本地的名称是在函数定义时确定的**“ 这正是我错过的!谢谢! – alvarosg

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) 

注意,对于foobasestring使用LOAD_FAST操作码检索(这意味着它正在寻找一个局部变量)。然而,在bar中,使用LOAD_GLOBAL操作码来检索basestring

相关问题