在PEP 366 - Main module explicit relative imports中引入了模块范围变量__package__
以允许子模块中的显式相对导入,有以下摘录:
当主模块由其文件名指定时,该
__package__
属性将设置为None
. 为了在直接执行模块时允许相对导入,在第一个相对导入语句之前需要类似于以下的样板:if __name__ == "__main__" and __package__ is None: __package__ = "expected.package.name"
请注意,只有当顶层包已经可以通过
sys.path
. 需要额外的操作代码sys.path
才能直接执行,而无需导入顶级包。这种方法也有与使用同级模块的绝对导入相同的缺点 - 如果脚本被移动到不同的包或子包,则需要手动更新样板。它的优点是,无论相对导入的数量如何,每个文件只需要进行一次更改。
我尝试在以下设置中使用此样板:
目录布局:
foo ├── bar.py └── baz.py
bar.py 子模块的内容:
if __name__ == "__main__" and __package__ is None: __package__ = "foo" from . import baz
当从文件系统执行子模块 bar.py 时样板工作(PYTHONPATH
修改使包 foo/ 可在 上访问sys.path
):
PYTHONPATH=$(pwd) python3 foo/bar.py
当从模块命名空间执行子模块 bar.py 时,样板也可以工作:
python3 -m foo.bar
但是,以下替代样板在这两种情况下都与 bar.py 子模块的内容一样有效:
if __package__:
from . import baz
else:
import baz
此外,这个替代样板更简单,并且当它与子模块 baz.py 一起移动到不同的包时不需要对子模块 bar.py 进行任何更新(因为它没有硬编码包名"foo"
)。
所以这是我关于 PEP 366 样板的问题:
- 第一个子表达式
__name__ == "__main__"
是必需的还是已经被第二个子表达式暗示了__package__ is None
? - 为了处理空字符串在哪里的情况(例如在通过提供包含目录从文件系统执行的子模块中:),不
__package__ is None
应该改为使用第二个子表达式吗?not __package__
__package__
__main__.py
PYTHONPATH=$(pwd) python3 foo/