前言
命名空间通俗的理解就是对象或变量的作用范围,在python中分为局部命令空间、模块命名空间和build-in全局命名空间。
局部命名空间
局部命名空间即在一个函数或一个类中起作用的变量或引用的字典集合,使用local()即可获得局部的命名空间,是一个字典。
class Person(object):
name = 'cai'
print(locals()) # {'__module__': '__main__', '__qualname__': 'Person', 'name': 'cai'}
locals()['age'] = 20
print(locals()) # {'__module__': '__main__', '__qualname__': 'Person', 'name': 'cai', 'age': 20}
def get_name(self):
print(locals()) # {'self': <__main__.Person object at 0x0000026BF6E35358>}
print(locals()) # {'__module__': '__main__', '__qualname__': 'Person', 'name': 'cai', 'age': 20, 'get_name': <function Person.get_name at 0x0000026BF6B74598>}
if __name__ == "__main__":
Person().get_name()
-
所有在类或函数中定义或引用的对象会被收集到该类或函数的局部命名空间中;
-
local()方法会获取当前所处位置的局部命名空间,可以手动往局部命名空间中添加键值对;
-
python作为解释型语言,代码上下文从上往下加载,其实就是不断往命名空间中添加对象的键值对;
模块命名空间
模块命名空间即在当前模块中的所有的对象的字典集合,使用globals()获取模块命名空间。
from test import name
import os
class Person(object):
pass
if __name__ == "__main__":
print(globals())
print(locals())
-
如果是在模块中直接使用globals()和locals()获取命名空间,它们得到的结果是一模一样的;
-
模块命名空间收集了所有隐藏属性、定义的对象或导入的模块或对象的字典集合;
-
从某个模块中导入一个对象,本质就是将该对象的键值对加入到模块的命名空间中,同理直接导入某个模块,就是将整个模块的命名空间导入到另一个模块。
全局命名空间
除了局部命名空间和模块命名空间外,还有一种就是全局命名空间了,全局命名空间中的对象在任何模块无需导入就可以直接使用,其本质上是python的builtins模块的命名空间。
l = list()
d = dict()
如list、dict等方法无需导入即可使用,原因是每个py模块有一个隐藏的属性_builtins_,该属性指向全局的命名空间所在的模块,相当于每次都自动加载了builtins模块的命名空间。
修改命名空间
程序的运行逻辑一般在方法或函数中,它们默认使用的局部命名空间,如果想要在函数中修改模块命名空间就需要将模块命名空间引入到局部命名空间中。
name = 'xiao'
def get():
x = 1
def name():
global name
nonlocal x
print(locals()) # {'x': 1}
x = 2
print(locals()) # {'x': 2}
name = 'cao'
return name
if __name__ == "__main__":
get()()
print(globals()) # {....,'name': 'cao', 'get': <function get at 0x0000029E49AB2EA0>}
-
通过global关键字可以将模块的命名空间中的变量引入到局部命名空间;nonlocal可以在闭包中将外层函数的命名空间引入到内层。
-
注意nonlocal关键字是不能在方法中将类的属性等引入到方法中进行修改的。
总结
-
全局命名空间在所有模块中可用,python自动加载,无需导入;
-
模块命名空间收集本模块所有的对象的键值对,所有模块层面代码执行时会从模块命名空间查找对象;
-
所有函数或方法中变量都只存在于局部命名空间,这使得各函数变量相互隔离。