Python作用域的规则小析
Python的作用域解析是基于叫做LEGB(Local(本地),Enclosing(封闭),Global(全局),Built-in(内置))的规则进行操作的。这看起来很直观,对吧?事实上,在Python中这有一些细微的地方很容易出错。看这个例子:
>>> x = 10
>>> def foo():
... x += 1
... print x
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment
这是怎么回事?
这是因为,在一个作用域里面给一个变量赋值(注意这里是赋值,如果是被引用的话没有这个问题)的时候,Python自动认为这个变量是这个作用域的本地变量,并屏蔽作用域外的同名的变量。
如果foo函数改成这个样子就没有问题:
>>> def foo():
... y = x
... x = y+1
... print y
很多时候可能在一个函数里添加一个赋值的语句会让你从前本来工作的代码得到一个UnboundLocalError。(感兴趣的话可以读一读这篇文章。)
在使用列表(lists)的时候,这种情况尤为突出。看下面这个例子:
>>> lst = [1, 2, 3]
>>> def foo1():
... lst.append(5) # 这没有问题...
...
>>> foo1()
>>> lst
[1, 2, 3, 5]
>>> lst = [1, 2, 3]
>>> def foo2():
... lst += [5] # ... 这就有问题了!
...
>>> foo2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'lst' referenced before assignment
嗯?为什么foo2有问题,而foo1没有问题?
答案和上一个例子一样,但是更加不易察觉。foo1并没有给lst赋值,但是foo2尝试给lst赋值。注意lst+=[5]只是lst=lst+[5]的简写,由此可以看到我们尝试给lst赋值(因此Python假设作用域为本地)。但是,这个要赋给lst的值是基于lst本身的(这里的作用域仍然是本地),而lst却没有被定义,这就出错了。
http://blog.jobbole.com/68256/