关于Python变量作用域的困惑
我遇到了一段让我有点困惑的代码。这里有一个简单的例子来展示这个问题:
# of course, the ... are not part of the actual code
some_var = {"key1":"value1" ... "keyN":"valueN"}
def some_func():
v = some_var["key1"]
这段代码可以正常运行,但我直接访问 some_var
这一点让我感到困惑。上一次我写 Python 代码的时候,我记得我得这样写 some_func
:
def some_func():
global some_var
v = some_var["key1"]
我在 Windows 7 的电脑上使用的是 Python 2.7.1。请问在 2.7 的版本中有什么变化,让我可以这样做吗?
6 个回答
在使用外部作用域的变量时,有一个区别:你可以用这个名字来调用它或者在表达式中使用它,但如果你要给它赋值,那就不一样了。而且,给一个普通变量赋值和给一个对象的成员赋值(比如 x.y = ...
或 x[...] = ...
)也是有区别的,这些赋值操作算作方法调用!
如果你要重新给一个外部作用域的变量赋值,你需要声明一下。在Python 2中,你只能对全局变量这样做(通过 global var
),而在Python 3中,你可以对任意嵌套的作用域(比如闭包)使用 nonlocal var
来处理。
在你的例子中,使用一个非局部变量是不需要 global
的。但是,一旦你在这个作用域内的任何地方给这个变量赋值(按照前面提到的赋值定义),你就需要声明了——所以如果你在使用它的那行后面加一行 some_var = ...
,你就会遇到 UnboundLocalError
错误。想了解更多细节,可以查阅文档。
只有当你想给一个变量赋新值时,才需要使用 global
。
嵌套作用域 是在 Python 2.1 中引入的(并且在 Python 2.2 中默认启用)(强调是我说的):
简单来说,当一个变量名在函数内部没有被赋值(比如没有通过赋值语句,或者
def
、class
、import
这些语句),那么对这个变量的引用会在外层作用域的本地命名空间中查找。关于规则的更详细解释和实现的分析,可以在 PEP 中找到。
不,你不能在局部范围内重新给 some_var
赋值。想想下面这个例子:
some_var = {}
def some_func():
# some_var[5] = 6
some_var = {1:2}
some_var[3] = 4
some_func()
print (repr(some_var)) # {}
你会发现,在 some_func
里面的赋值其实是创建了一个局部变量,这个局部变量会遮盖掉全局的那个变量。所以,如果你把那行代码的注释去掉,就会出现 UnboundLocalError
错误——也就是说,你不能在变量定义之前就去访问它。