模块命名空间中的定义顺序是不是可用?
Posted
技术标签:
【中文标题】模块命名空间中的定义顺序是不是可用?【英文标题】:Is definition order available in a module namespace?模块命名空间中的定义顺序是否可用? 【发布时间】:2017-08-05 13:18:29 【问题描述】:据记载,definition order in classes is preserved(另见PEP 520):
如果元类没有
__prepare__
属性,则类命名空间被初始化为空的有序映射。
模块对象中是否也保留了定义顺序?
# foo_bar.py
def foo():
pass
def bar():
pass
我已经尝试过上面的模块(也交换了顺序),它似乎确实可靠:
>>> import foo_bar
>>> for name in foo_bar.__dict__:
... if not name.startswith('_'):
... print(name)
...
foo
bar
据推测,模块命名空间也在下面使用了一个紧凑的字典,或者可能是因为type(foo_bar)
是一个<class 'module'>
,它也必须像任何其他类一样尊重定义顺序。但是,我不确定这是 Python 保证的功能,还是只是 CPython 实现细节。 模块中的名称是否必须遵守定义顺序?
【问题讨论】:
据我所知,这是一个实现细节。稍后可能会做出明确的保证,或者只是从如何指定模块级名称定义和如何指定 dict order 的组合中做出的隐含保证,一旦 dict order 实际上是规范的一部分。 请注意foo_bar
不是一个类。您似乎对type(foo_bar)
在输出中的class
感到困惑。输出中的class
仅表示type(foo_bar)
是一个类;这并不意味着foo_bar
本身就是一个。
不,我的建议是这样的:类 -> instance=Class() -> 实例属性尊重排序,因为命名空间使用紧凑字典。 ModuleType -> module=ModuleType() -> 模块属性尊重排序 (?) 因为命名空间使用紧凑型字典 (?)。
即一个模块“只是”ModuleType
类的一个实例。
排序保证尚未扩展到其实例具有__dict__
的所有类的所有实例。这仍然是一个实现细节。
【参考方案1】:
内置类,如module
类,不通过用户定义类的正常机制do*,因此,不要使用metaclass.__prepare__
. PEP 520
不适用于它们,因此它所扩展的保证不能在这里应用。
由于字典被插入排序,因此模块命名空间的顺序当前被保留,因此与字典本身一样,被视为实现细节。
* 用户定义的类首先通过bltinmodule.c
中的build_class
(当你dis
一个类语句时LOAD_BUILD_CLASS
字节码加载的函数)。这是__prepare__
is invoked 的唯一位置(如果未定义带有__prepare__
的自定义元,则returns a PyDict_New
来自type_prepare
)。
【讨论】:
模块命名空间使用什么类型的存储后端,它是在哪里创建的?我听说它在某处说它是一种针对字符串键优化的特殊字典,但是当我在 REPL 中检查它时,它似乎只是一个普通的字典,我能够使用非字符串键设置项没有问题。跨度> 我很确定它是在导入机制的内部创建的,但我必须对此进行调查并回复您@wim。你说的那种特殊的dict可能是the key-sharing one that exists for instances,但我真的不知道它是否也用于模块。以上是关于模块命名空间中的定义顺序是不是可用?的主要内容,如果未能解决你的问题,请参考以下文章