分享

Python 名字空间

 shawnsun007 2022-05-07 发布于北京
名字空间是 Python 最核⼼心的内容。
>>> x
NameError: name 'x' is not defined
我们习惯于将 x 称为变量,但在这⾥里,更准确的词语是 "名字"。
和 C 变量名是内存地址别名不同,Python 的名字实际上是⼀一个字符串对象,它和所指向的⺫⽬目标对
象⼀一起在名字空间中构成⼀一项 {name: object} 关联。
Python 有多种名字空间,⽐比如称为 globals 的模块名字空间,称为 locals 的函数堆栈帧名字空
间,还有 class、instance 名字空间。不同的名字空间决定了对象的作⽤用域和⽣生存周期。
>>> x = 123
>>> globals()? ? ? ? # 获取 module 名字空间。
{'x': 123, ......}
可以看出,名字空间就是⼀一个字典 (dict)。我们完全可以直接在名字空间添加项来创建名字。
>>> globals()["y"] = "Hello, World!"
>>> y
'Hello, World!'
在 Python 源码中,有这样⼀一句话:Names have no type, but objects do.
12
名字的作⽤用仅仅是在某个时刻与名字空间中的某个对象进⾏行关联。其本⾝身不包含⺫⽬目标对象的任何信
息,只有通过对象头部的类型指针才能获知其具体类型,进⽽而查找其相关成员数据。正因为名字的
弱类型特征,我们可以在运⾏行期随时将其关联到任何类型对象。
>>> y
'Hello, World!'
>>> type(y)
<type 'str'>
>>> y = __import__("string")? # 将原本与字符串关联的名字指向模块对象。
>>> type(y)
<type 'module'>
>>> y.digits?? ? ? # 查看模块对象的成员。
'0123456789'
在函数外部,locals() 和 globals() 作⽤用完全相同。⽽而当在函数内部调⽤用时,locals() 则是获取当前
函数堆栈帧的名字空间,其中存储的是函数参数、局部变量等信息。
>>> import sys
>>> globals() is locals()
True
>>> locals()
{
? '__builtins__': <module '__builtin__' (built-in)>,
? '__name__': '__main__',
? 'sys': <module 'sys' (built-in)>,
}
>>> def test(x):? ? ? ? ? # 请对⽐比下⾯面的输出内容。
... y = x + 100
... print locals()? ? ? ? # 可以看到 locals 名字空间中包含当前局部变量。
... print globals() is locals()? ? # 此时 locals 和 globals 指向不同名字空间。
... frame = sys._getframe(0)? ? ? # _getframe(0) 获取当前堆栈帧。
... print locals() is frame.f_locals? ? # locals 名字空间实际就是当前堆栈帧的名字空间。
... print globals() is frame.f_globals? # 通过 frame 我们也可以函数定义模块的名字空间。
>>> test(123)
{'y': 223, 'x': 123}
False
True
True
13
在函数中调⽤用 globals() 时,总是获取包含该函数定义的模块名字空间,⽽而⾮非调⽤用处。
>>> pycat test.py
a = 1
def test():
print {k:v for k, v in globals().items() if k != "__builtins__"}
>>> import test
>>> test.test()
{
? '__file__': 'test.pyc',
? '__name__': 'test',
? 'a': 1,
? 'test': <function test at 0x10bd85e60>,
}
可通过 <module>.__dict__ 访问其他模块的名字空间。
>>> test.__dict__? ? ? ? ? ? # test 模块的名字空间
{
? '__file__': 'test.pyc',
? '__name__': 'test',
? 'a': 1,
? 'test': <function test at 0x10bd85e60>,
}
>>> import sys
>>> sys.modules[__name__].__dict__ is globals()? # 当前模块名字空间和 globals 相同。
True
与名字空间有关的内容很多,⽐比如作⽤用域、LEGB 查找规则、成员查找规则等等。所有这些,都将
在相关章节中给出详细说明。
使⽤用名字空间管理上下⽂文对象,带来⽆无与伦⽐比的灵活性,但也牺牲了执⾏行性能。毕竟从字典中查找
对象远⽐比指针低效很多,各有得失。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多