深入理解Python命名空间:局部、全局与内置命名空间详解
Python通过名为命名空间的事物来记录变量的踪迹。命名空间就是一个字典,其中的键字是变量名,而字典的值是那些变量的值。实际上,能够像访问 Python 的字典那样去访问命名空间,稍后我们就会看到这一点。

[id_[id_562729351]3285996]内置命名空间是存在的,任何模块都能够访问它,并且它里面存放着内置的函数和异常。
当一行代码需要使用变量 x 的值时,Python 会在所有可用的名字空间中去查找该变量,查找顺序如下:
本地的,也就是特指当前函数或类的方法。若函数定义了一个局部变量 x,那么 Python 会使用这个变量,接着就会停止搜索。
在函数体内定义了一个新的函数,此函数处于封闭状态。
全局的(Global)指的是当前的模块。如果模块定义了一个名为 x 的变量、函数或者类,Python 就会使用这个变量,接着停止搜索。
内置的情况是对每个模块都为全局的。在进行最后的尝试时,Python 会假设 x 是内置函数或者变量。
如果 Python 在这些名字空间中找不到 x,它就会放弃查找。接着,它会引发一个 NameError 的异常,并且传递 There is no variable named ‘x’ 这样的信息。
像 Python 里的诸多事情那样,名字空间在运行时能够直接被访问。具体而言,局部名字空间可以借助内置的 locals 函数来进行访问。而全局(模块级别)名字空间则可以通过 globals 函数来进行访问。并且这两者返回的都是字典 dict 类型。
locals()介绍:
>>> def test(arg):
函数 foo 的局部名字空间中有两个变量,一个是 arg,它的值被传入函数;另一个是 z,它是在函数里定义的。
z = 1
print locals()
>>> test(4)
locals 会返回一个由名字和值组成的字典。该字典的键是字符串形式的变量名,而字典的值则是变量的实际值。
用 4 来调用 foo ,会打印出一个字典,这个字典包含函数的两个局部变量,即 arg (4) 和 z (1) 。
{'z': 1, 'arg': 4}
>>> test('doulaixuexi')
#locals 可以用于所有类型的变量。
{'z': 1, 'arg': 'doulaixuexi'}
>>>
globals()介绍:
>>> from sys import *
>>> print globals()
{'setrecursionlimit': in function setrecursionlimit>,
'dont_write_bytecode': False,
获取文件系统编码。: in function getfilesystemencoding>,
'long_info'系统的长信息中包含每个数字的位数为15, sizeof_digit=2),
'stdout': at 0x02110850>,
'text': <function text at 0x02111A70>,
'meta_path': [],
'exc_clear': in function exc_clear>,
'prefix': 'C:\\Python27', 'getrefcount': in function getrefcount
globals 函数会返回一个字典,这个字典包含了所有的全局变量,其中也包括所有被导入的变量。
locals()与globals()对比:
b = 5 # 定义一个全局变量
def test2():
a=1
locals()["a"] = 2 # 修改局部变量
print "a=", a
globals()["b"] = 6 # 修改全局变量
print "b=", b
if __name__ == '__main__':
test2()
输出:
a= 1
b= 6
locals() 所返回的是当前局部变量的一个深拷贝。当对 locals() 中的变量值进行修改时,实际上并不会对原变量本身产生任何影响。而 globals() 返回的是全局变量的字典,要是对其中的内容进行修改,其值就会真正地发生改变。
对于局部赋值需要注意如下:
myVar = 27
def myFunction(param1=123,param2="Python"):
for key,val in locals().items():
print "key %s : %s" % (key,str(val))
myVar = myVar + 1
myFunction(123456,435465)
将会报错:
UnboundLocalError: local variable 'myVar' referenced before assignment
原因如下:
Python有这样的假设,在函数体内的某个地方对变量进行赋值时,Python 会将该名称添加到局部命名空间中。像语句 myVar = myVar + 1 这样的情况,它是对名称 myVar 进行赋值操作。Python 假设,无论在何处发生赋值这种行为,myVar 都属于函数 myFunction 的局部命名空间的一部分。Python尝试把 1 添加到 myVar 中,此时该名称处于局部命名空间内,然而它并没有关联值,所以会报错。
问题在于 Python 决定 myVar 出现在局部空间的时间,这在代码运行之前就发生了,也就是在 Python 运行到函数定义之前。因为在创建局部命名空间时(代码实际运行之前),Python 会对代码进行检查并填充局部命名空间。在 Python 运行那行代码之前,就已经发现了对 myVar 的赋值,并将其添加到了局部命名空间中。函数执行时,Python 解释器觉得 myVar 在局部命名空间里,然而却没有值,于是就会引发错误。
解决办法:在函数体内,若使用 global 语句把变量声明为全局变量,那么 Python 就不会在命名空间中为该变量创建局部名称。
myVar = 27
def myFunction(param1=123,param2="Python"):
global myVar
for key,val in locals().items():
print "key %s : %s" % (key,str(val))
myVar = myVar + 1
myFunction(123456,435465)