已添加__init__.py,导入父包后为何无法访问子包?如何批量导入?
Python父包导入后无法直接访问子包的问题解析与解决方法
问题现象
即使所有文件夹都包含__init__.py文件,导入父包后仍无法直接加载其子包。
示例操作
创建目录结构:
mkdir -p parent/child touch parent/__init__.py touch parent/child/__init__.py
最终目录结构如下:
$ tree parent parent ├── child │ ├── file.py │ └── __init__.py └── __init__.py
在Python交互环境中执行:
$ python3 Python 3.11.0 (main, Oct 26 2022, 14:04:35) [GCC 10.2.1 20210110] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import parent >>> parent.child Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: module 'parent' has no attribute 'child'
显式导入子包可正常工作:
>>> from parent import child
但子目录较多时,逐个显式导入十分繁琐。
问题原因
Python的包导入机制默认不会自动递归加载子包。当你执行import parent时,Python只会加载父包目录下的__init__.py文件,将父包加入当前命名空间,但不会主动扫描并导入所有子包。因此,父包的命名空间中不存在子包的引用,直接访问parent.child就会触发AttributeError。
解决方法
要让子包能通过父包直接访问,核心是在父包的__init__.py中显式导入子包,或者通过代码自动批量导入子包。
方法1:手动显式导入子包
在parent/__init__.py中添加子包的导入语句:
# parent/__init__.py from . import child # 多子包场景依次添加 # from . import child2 # from . import child3
之后再执行import parent,就能直接通过parent.child访问子包了。
方法2:自动批量导入所有子包
如果子包数量较多,手动导入太繁琐,可以在父包的__init__.py中编写代码,自动扫描并导入所有符合条件的子包:
# parent/__init__.py import os import importlib # 获取父包所在目录 package_dir = os.path.dirname(__file__) # 遍历目录下的所有子项 for item in os.listdir(package_dir): item_path = os.path.join(package_dir, item) # 判断是否是有效子包目录(排除__pycache__等特殊目录,且存在__init__.py) if os.path.isdir(item_path) and not item.startswith("__"): init_file = os.path.join(item_path, "__init__.py") if os.path.exists(init_file): # 导入子包 importlib.import_module(f".{item}", __name__)
这种方式会自动导入父包目录下所有包含__init__.py的子目录作为子包,无需手动逐个添加导入语句。
注意事项
- 自动导入可能会导入不需要的子包,增加初始化时间,建议仅在明确需要所有子包的场景下使用。
- 如果子包名称与父包内的其他变量/模块名称冲突,会导致命名覆盖问题,需提前规划好包结构。
内容的提问来源于stack exchange,提问作者Hielke Walinga
相关产品推荐
相关产品推荐

