为什么在子包的 __init__.py 中导入特定子包模块的方法会用子包填充包命名空间?
Why does importing a specific subpackage module's method in the subpackage's __init__.py populate the package namespace with the subpackage?
我用的是Python3.9.10
我知道提出的问题相当冗长和令人困惑,但是我想不出更好的措辞方式,所以请允许我在下面说明问题:
我有一个包,test_import
,结构如下:
test_import/
├── __init__.py
├── moduleA.py
└── moduleB/
├── __init__.py
└── moduleB.py
test_import/__init__.py
包含以下内容:
from . import moduleA
from . import moduleB
test_import/moduleA.py
包含以下内容:
def test_func_module_a(s: str):
print(f"test_import.moduleA.test_func_module_a : {s}")
test_import/moduleB/moduleB.py
包含以下内容:
def test_func_module_b(s: str):
print(f"test_import.moduleB.moduleB.test_func_module_b: {s}")
最后,test_import/moduleB/__init__.py
包含以下内容:
from .moduleB import test_func_module_b
最后,我的 $PYTHONPATH
中有 test_import
,我有一个 python 文件 test_main.py
,它导入并使用(不太有用的) test_import
图书馆:
import test_import as ti
ti.moduleA.test_func_module_a("ti.moduleA.test_func_module_a")
ti.moduleB.test_func_module_b("ti.moduleB.test_func_module_b")
ti.moduleB.moduleB.test_func_module_b("ti.moduleB.moduleB.test_func_module_b")
当我 运行 test_main.py
时,我希望看到以下内容:
my.username@myMac:Desktop$ python3 test_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
test_import.moduleB.moduleB.test_func_module_b: ti.moduleB.test_func_module_b
Traceback (most recent call last):
File "/Users/my.username/Desktop/test_import_main.py", line 11, in <module>
ti.moduleB.moduleB.test_func_module_b("ti.moduleB.moduleB.test_func_module_b")
AttributeError: module 'test_import.moduleB' has no attribute 'moduleB'
我希望看到这个,因为在 test_import/__init__.py
中,我只将特定方法 test_func_module_b
导入到属于 test_import.moduleB
的名称空间中。我没有在 test_import/moduleB/__init__.py
中导入 moduleB.py
模块,即 from . import moduleB
.
但是,当我 运行 test_main.py
时,我得到以下结果,没有引发任何与名称空间相关的 AttributeError:
my.username@myMac:Desktop$ python3 test_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
test_import.moduleB.moduleB.test_func_module_b: ti.moduleB.test_func_module_b
test_import.moduleB.moduleB.test_func_module_b: ti.moduleB.moduleB.test_func_module_b
即没有与 test_import.moduleB
命名空间相关的 AttributeError。
这令人困惑,因为(正如我上面所说),我没有将 moduleB.py
导入 test_import.moduleB
的命名空间。
如果我将 test_import/__init__.py
保留为一个空文件,并且 运行 test_main.py
,以下两行都会引发 AttributeError
s,与缺少在子包的 (test_import.moduleB
) 命名空间中,即:
my.username@myMac:Desktop$ python3 test_import_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
Traceback (most recent call last):
File "/Users/my.username/Desktop/test_import_main.py", line 10, in <module>
ti.moduleB.test_func_module_b("ti.moduleB.test_func_module_b")
AttributeError: module 'test_import.moduleB' has no attribute 'test_func_module_b'
和
my.username@myMac:Desktop$ python3 test_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
Traceback (most recent call last):
File "/Users/my.username/Desktop/test_import_main.py", line 11, in <module>
ti.moduleB.moduleB.test_func_module_b("ti.moduleB.moduleB.test_func_module_b")
AttributeError: module 'test_import.moduleB' has no attribute 'moduleB'
谁能解释一下 Python 的导入系统是如何做到这一点的?
PS - 由于 Whosebug 上有很多与导入相关的问题,我希望会有类似的问题。但是,我一直找不到这个特定问题的答案。
当 Python 作为导入的一部分遇到 子模块时 (from x.y import z
中的 y
(绝对)或 from .y import z
(相对)),它将在父模块的命名空间中放置对子模块的引用。 the docs:
中对此进行了概述
When a submodule is loaded using any mechanism [...] a binding is placed in the parent module’s namespace to the submodule object.
[...]
The invariant holding is that if you have sys.modules['spam']
and sys.modules['spam.foo']
[...] the latter must appear as the foo
attribute of the former.
我用的是Python3.9.10
我知道提出的问题相当冗长和令人困惑,但是我想不出更好的措辞方式,所以请允许我在下面说明问题:
我有一个包,test_import
,结构如下:
test_import/
├── __init__.py
├── moduleA.py
└── moduleB/
├── __init__.py
└── moduleB.py
test_import/__init__.py
包含以下内容:
from . import moduleA
from . import moduleB
test_import/moduleA.py
包含以下内容:
def test_func_module_a(s: str):
print(f"test_import.moduleA.test_func_module_a : {s}")
test_import/moduleB/moduleB.py
包含以下内容:
def test_func_module_b(s: str):
print(f"test_import.moduleB.moduleB.test_func_module_b: {s}")
最后,test_import/moduleB/__init__.py
包含以下内容:
from .moduleB import test_func_module_b
最后,我的 $PYTHONPATH
中有 test_import
,我有一个 python 文件 test_main.py
,它导入并使用(不太有用的) test_import
图书馆:
import test_import as ti
ti.moduleA.test_func_module_a("ti.moduleA.test_func_module_a")
ti.moduleB.test_func_module_b("ti.moduleB.test_func_module_b")
ti.moduleB.moduleB.test_func_module_b("ti.moduleB.moduleB.test_func_module_b")
当我 运行 test_main.py
时,我希望看到以下内容:
my.username@myMac:Desktop$ python3 test_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
test_import.moduleB.moduleB.test_func_module_b: ti.moduleB.test_func_module_b
Traceback (most recent call last):
File "/Users/my.username/Desktop/test_import_main.py", line 11, in <module>
ti.moduleB.moduleB.test_func_module_b("ti.moduleB.moduleB.test_func_module_b")
AttributeError: module 'test_import.moduleB' has no attribute 'moduleB'
我希望看到这个,因为在 test_import/__init__.py
中,我只将特定方法 test_func_module_b
导入到属于 test_import.moduleB
的名称空间中。我没有在 test_import/moduleB/__init__.py
中导入 moduleB.py
模块,即 from . import moduleB
.
但是,当我 运行 test_main.py
时,我得到以下结果,没有引发任何与名称空间相关的 AttributeError:
my.username@myMac:Desktop$ python3 test_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
test_import.moduleB.moduleB.test_func_module_b: ti.moduleB.test_func_module_b
test_import.moduleB.moduleB.test_func_module_b: ti.moduleB.moduleB.test_func_module_b
即没有与 test_import.moduleB
命名空间相关的 AttributeError。
这令人困惑,因为(正如我上面所说),我没有将 moduleB.py
导入 test_import.moduleB
的命名空间。
如果我将 test_import/__init__.py
保留为一个空文件,并且 运行 test_main.py
,以下两行都会引发 AttributeError
s,与缺少在子包的 (test_import.moduleB
) 命名空间中,即:
my.username@myMac:Desktop$ python3 test_import_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
Traceback (most recent call last):
File "/Users/my.username/Desktop/test_import_main.py", line 10, in <module>
ti.moduleB.test_func_module_b("ti.moduleB.test_func_module_b")
AttributeError: module 'test_import.moduleB' has no attribute 'test_func_module_b'
和
my.username@myMac:Desktop$ python3 test_main.py
test_import.moduleA.test_func_module_a : ti.moduleA.test_func_module_a
Traceback (most recent call last):
File "/Users/my.username/Desktop/test_import_main.py", line 11, in <module>
ti.moduleB.moduleB.test_func_module_b("ti.moduleB.moduleB.test_func_module_b")
AttributeError: module 'test_import.moduleB' has no attribute 'moduleB'
谁能解释一下 Python 的导入系统是如何做到这一点的?
PS - 由于 Whosebug 上有很多与导入相关的问题,我希望会有类似的问题。但是,我一直找不到这个特定问题的答案。
当 Python 作为导入的一部分遇到 子模块时 (from x.y import z
中的 y
(绝对)或 from .y import z
(相对)),它将在父模块的命名空间中放置对子模块的引用。 the docs:
When a submodule is loaded using any mechanism [...] a binding is placed in the parent module’s namespace to the submodule object.
[...]
The invariant holding is that if you havesys.modules['spam']
andsys.modules['spam.foo']
[...] the latter must appear as thefoo
attribute of the former.