Python中父模块与子模块存在同名文件时如何实现正确导入?
问题根源
这个现象是Python通配导入import *的正常逻辑,和父子模块同名没有特殊关系:
- 执行
from X import *时,Python会把X模块命名空间内所有公开属性(无下划线前缀的名字,或__all__列表明确指定的名字)直接复制到当前模块的命名空间,如果存在重名,后导入的内容会直接覆盖之前绑定的同名对象。 - 你当前的外层
__init__.py先导入了外层的a、b模块,随后执行from .test import *时,test包的__init__.py已经把test内部的a、b模块注册成了test包的顶层属性,这两个同名a、b被通配导入复制到module的命名空间后,直接覆盖了之前导入的外层a、b,就出现了你看到的结果。
可行解决方案
方案1:最小改动,调整导入方式避免命名污染
直接修改外层module/__init__.py,不要用通配符导入test包的全部内容,改为显式导入test子包本身即可,不需要改其他文件:
# module/__init__.py from . import test # 仅绑定test子包到module命名空间,不会导入test内部的a、b from .a import * from .b import *
修改后效果完全符合预期:
module.a指向外层./module/a.pymodule.b指向外层./module/b.pymodule.test指向test子包,module.test.a、module.test.b正常指向test目录下的对应文件
方案2:通过__all__限制通配导入的导出范围
如果必须保留from .test import *的写法,可以在test包的__init__.py中显式定义__all__列表,指定允许被通配导入对外暴露的名字,不要把内部的a、b暴露到外层:
# module/test/__init__.py from .a import * from .b import * # 仅列出需要透传到外层module的接口,a、b不要加入列表 __all__ = [] # 有其他需要暴露的函数、类可以自行添加到列表中
同时调整外层module/__init__.py的导入顺序,让外层自己的a、b最后导入,避免被覆盖:
# module/__init__.py from .test import * from .a import * from .b import *
这种方式的局限性是如果test包有需要透传到外层的同名属性,依然会产生冲突,适合test包不需要向外层透传内部模块的场景。
方案3:弃用通配导入,使用精确导入(工程化推荐)
Python项目中不推荐使用import *的写法,很容易产生命名空间污染和意外覆盖,最稳妥的方式是全部使用显式精确导入:
# module/__init__.py from . import a, b, test # 如果需要把a、b中的特定接口暴露到module顶层,单独显式导入即可,例如: # from .a import some_func # from .b import SomeClass
这种写法下命名空间完全清晰,不会出现任何意外覆盖:
- 外层a模块固定通过
module.a访问 - test子包下的a模块固定通过
module.test.a访问
是中大型Python项目普遍采用的导入规范。
内容的提问来源于stack exchange,提问作者chanjure
相关产品推荐
相关产品推荐

