如果代码风格相对而言不是那么的Pythonic,或许很少碰到这类错误。当然并不是不鼓励使用一些python语言的技巧。如果遇到这这种类型的错误,说明我们对python中变量引用相关部分有不当的认识和理解。而这又是对理解python相关概念比较重要的。这也是本文写作的原因。
本文为理解闭包相关概念的做铺垫,后续会详细深入的整理出闭包相关的博文,敬请关注。
1.案例分析在整理闭包相关概念的过程中,经常发现UnboundLocalError和NameError这两个错误,刚开始遇到的时候可能很困惑,对这样的错误无从下手。
1.1 案例一:def outer_func():
loc_var = "local variable"
def inner_func():
loc_var += " in inner func"
return loc_var
return inner_func
clo_func = outer_func()
clo_func()
错误提示:
Traceback (most recent call last): File "G:\Project Files\Python Test\Main.py", line 238, in <module> clo_func() File "G:\Project Files\Python Test\Main.py", line 233, in inner_func loc_var += " in inner func" UnboundLocalError: local variable 'loc_var' referenced before assignment
1.2 案例二:1 def get_select_desc(name, flag, is_format = True): 2 if flag: 3 sel_res = 'Do select name = %s' % name 4 return sel_res if is_format else name 5 6 get_select_desc('Error', False, True)
错误提示:
Traceback (most recent call last): File "G:\Project Files\Python Test\Main.py", line 247, in <module> get_select_desc('Error', False, True) File "G:\Project Files\Python Test\Main.py", line 245, in get_select_desc return sel_res if is_format else name UnboundLocalError: local variable 'sel_res' referenced before assignment
1.3 案例三:def outer_func(out_flag):
if out_flag:
loc_var1 = 'local variable with flag'
else:
loc_var2 = 'local variable without flag'
def inner_func(in_flag):
return loc_var1 if in_flag else loc_var2
return inner_func
clo_func = outer_func(True)
print clo_func(False)
错误提示:
Traceback (most recent call last): File "G:\Project Files\Python Test\Main.py", line 260, in <module> print clo_func(False) File "G:\Project Files\Python Test\Main.py", line 256, in inner_func return loc_var1 if in_flag else loc_var2 NameError: free variable 'loc_var2' referenced before assignment in enclosing scope
上面的三个例子可能显得有点矫揉造作,但是实际上类似错误的代码都或多或少可以在上面的例子中找到影子。这里仅仅为了说明相关概念,对例子本身的合理性不必做过多的关注。
2.错误原因由于python中没有变量、函数或者类的声明概念。按照C或者C++的习惯编写python,或许很难发现错误的根源在哪。
首先看一下这类错误的官方解释:
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.
大概意思是:
如果引用了某个变量,但是变量名没有找到,该类型的错误就是NameError。如果该名字是一个还没有被绑定的局部变量名,那么该类型的错误是NameError中的UnboundLocalError错误。
下面的这种NameError类型的错误或许还好理解一些:
1 my_function() 2 def my_function(): 3 pass