Python 3 导入优先级与 __init__.py



鉴于以下内容(请注意test错误地test包中内置阴影,我应该将其命名为tests,我们将在问题后面回到这个问题(

├── test
│   └── test_request_billing_id.py
└── requets_billing_id.py

在 Python shell 中时,尝试运行from test import test_request_billing_id 它给出了ImportError: cannot import name 'test_request_billing_id',它正在尝试导入内置的test包而不是我自己的test文件夹。

这可以通过运行此有效导入来验证

from test import support

问题1:

鉴于 Python3 允许隐式命名空间包,这意味着我的test文件夹也是一个包,我想内置的test包比我自己的test包具有更高的优先级?

问题2:

我在自己的test文件夹中创建了__init__.py,如下所示:

├── test
│   ├── __init__.py
│   └── test_request_billing_id.py
└── requets_billing_id.py

并再次运行相同的导入语句,它工作正常。

from test import test_request_billing_id

通过运行此无效导入来验证隐藏内置test

from test import support给出错误:ImportError: cannot import name 'support'

在我看来,__init__.py告诉 python 解释器让我的test影子是内置的test包。

有人可以解释一下吗,或者这在任何地方都有记录吗?

是的,带有__init__.py的包优先。这在 PEP 的这一部分中进行了解释:

在进口加工过程中,进口机械将继续 像在 Python 中一样遍历父路径中的每个目录 3.2. 在查找名为 "foo" 的模块或软件包时,对于父路径中的每个目录:

  • 如果找到<directory>/foo/__init__.py,则导入并返回常规包。
  • 如果不是,但找到<directory>/foo.{py,pyc,so,pyd},则导入并返回模块。扩展的确切列表因平台而异 以及是否指定了 -O 标志。这里的列表具有代表性。
  • 如果没有,但找到<directory>/foo并且是一个目录,则会记录它,然后继续扫描父目录中的下一个目录 路径。
  • 否则,扫描将继续使用父路径中的下一个目录。

如果在搜索过程中遇到任何命名空间包,则会"记录"它们并继续搜索。如果稍后找到包含__init__.py的包,则会丢弃"记录的"命名空间包,而是导入带有__init__.py的包。

这正是当您的test包没有__init__.py时发生的情况 - 标准库中的test确实有一个__init__.py,因此它优先于您的命名空间test包。

最新更新