模块命名空间中的定义顺序是不是可用?

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,但我真的不知道它是否也用于模块。

以上是关于模块命名空间中的定义顺序是不是可用?的主要内容,如果未能解决你的问题,请参考以下文章

Python之命名空间闭包装饰器

Python Day27

Django(命名空间)

命名空间

F# 中模块和命名空间之间的区别

从0开始的TypeScriptの十一:模块和命名空间