Following system colour scheme - Python 增强提案 Selected dark colour scheme - Python 增强提案 Selected light colour scheme - Python 增强提案

Python 增强提案

PEP 366 – 主模块显式相对导入

作者:
Alyssa Coghlan <ncoghlan at gmail.com>
状态:
最终版
类型:
标准跟踪
创建日期:
2007年5月1日
Python 版本:
2.6, 3.0
发布历史:
2007年5月1日,2007年7月4日,2007年7月7日,2007年11月23日

目录

摘要

本PEP提出了一种向后兼容的机制,允许从包内的可执行模块使用显式相对导入。目前,由于PEP 328PEP 338之间不协调的交互,此类导入会失败。

通过添加一个新的模块级属性,本PEP允许在模块使用-m开关执行时,相对导入自动工作。模块本身的一小段样板代码将允许在文件按名称执行时,相对导入也能工作。

Guido于2007年11月接受了该PEP[5]

提议的更改

主要的提议变更是引入一个新的模块级属性__package__。当它存在时,相对导入将基于此属性而不是模块的__name__属性。

与当前的__name__属性一样,设置__package__将由用于导入模块的PEP 302加载器负责。使用imp.new_module()创建模块对象的加载器将自动把新属性设置为None。当导入系统在未设置__package__(或设置为None)的模块中遇到显式相对导入时,它将计算并存储正确的值(对于普通模块为__name__.rpartition('.')[0],对于包初始化模块为__name__)。如果__package__已经设置,则导入系统将优先使用它,而不是从__name____path__属性重新计算包名。

runpy模块将显式设置新属性,其基础是用于定位要执行模块的名称,而不是用于设置模块__name__属性的名称。这将允许从使用-m开关执行的主模块进行相对导入正常工作。

当主模块由其文件名指定时,__package__属性将被设置为None。为了允许在模块直接执行时进行相对导入,需要在第一个相对导入语句之前添加类似于以下内容的样板代码

if __name__ == "__main__" and __package__ is None:
    __package__ = "expected.package.name"

请注意,此样板代码仅在顶级包已通过sys.path可访问时才足够。为了使直接执行在顶级包尚未可导入的情况下工作,还需要操纵sys.path的额外代码。

这种方法还存在与使用同级模块的绝对导入相同的缺点——如果脚本被移动到不同的包或子包中,样板代码需要手动更新。它的优点是,无论相对导入的数量如何,此更改只需在每个文件中进行一次。

请注意,明确将__package__设置为空字符串是允许的,并且会禁用该模块的所有相对导入(因为在这种情况下,导入机制会将其视为顶级模块)。这意味着像runpy这样的工具在设置__package__时不需要对顶级模块进行特殊处理。

变更理由

目前无法从主模块使用显式相对导入的问题是至少一个开放的SF错误报告(#1510172)的主题[1],并且很可能导致了comp.lang.python上的至少一些查询(例如Alan Isaac在[2]中的问题)。

本PEP旨在提供一个解决方案,允许从主模块进行显式相对导入,而不会在解释器启动或正常模块导入期间产生任何显著成本。

PEP 338中关于相对导入和主模块的部分提供了关于此问题的进一步细节和背景。

参考实现

SVN中的Rev 47142实现了此提案的早期变体,它将主模块的真实模块名存储在__module_name__属性中。由于当时2.5已进入beta阶段,它被还原了。

补丁1487[4]是本PEP的提议实现。

替代方案

PEP 3122提议通过改变主模块的识别方式来解决这个问题。为了修复一个在整体方案中相当小的错误而付出如此大的兼容性成本是不可取的,因此该PEP被拒绝了[3]

本PEP中提案的优点是,它对普通代码的唯一影响是导入模块时设置额外属性所需的一小部分时间。相对导入本身应该会略微加快,因为包名被缓存到模块全局变量中,而不是每次相对导入时都必须重新计算。

参考资料


来源:https://github.com/python/peps/blob/main/peps/pep-0366.rst

最后修改:2025-02-01 08:59:27 GMT