学习路线:B站
1.没有__init__文件时
目录结构:
├── moduleA.py
└── main.py
moduleA.py
的内容如下:
print("moduleA is imported")
main.py
内容如下:
import moduleA
运行main.py
会打印输出如下:
moduleA is imported
2.导入一个package
目录结构如下:
├── packageA
└── moduleA.py
└── main.py
其中moduleA.py
内容如下:
print("moduleA is imported")
main.py
内容如下:
import packageA
运行main.py时,什么都不会打印。因为我们引入packageA
并不会执行packageA
中的moduleA.py
,而是会执行一个__init__.py
(目前我们还没有建立)。
3.重新导入package
目录结构如下:
├── packageA
├── __init__.py
└── moduleA.py
└── main.py
其中__init__.py
内容如下:
print("packageA is imported")
其中moduleA.py
内容如下:
print("moduleA is imported")
main.py
内容如下:
import packageA
运行main.py
时,可以看到执行了__init__.py
,输出:
packageA is imported
说明我们导入一个package
时,会自动执行这个package
中的__init__.py
文件。
注意这里没有输出
moduleA is imported
说明,只是自动执行了__init__.py
而不会自动执行moduleA.py
应该往__init__.py文件中放什么
- 包的初始化,有的包需要环境变量,有的包需要配置logging
- 包的公共接口,即包需要被外面使用的东西。
例如
moduleA.py
内容如下:x = 'moduleA constant'
main.py
内容如下:from packageA import x
执行main.py会报错:ImportError: cannot import name ‘x’ from ‘packageA’
如果想要在
main.py
中导入moduleA.py
中的变量,需要再packageA
中的__init__.py
添加相对导入:from .moduleA import x
这样就可以在main.py中执行x了
有时候我们会在main.py
中导入packageA
中的所有内容,例如main.py
内容如下:
from packageA import *
print(x)
print(moduleA.x)
packageA
中的__init__.py
内容如下:
from . import moduleA # 默认就有这一行,最好写上这一行,逻辑更清晰一些
from .moduleA import x
__all__ = ['moduleA', 'x']
print("packageA is imported")
moduleA.py
内容如下:
print("moduleA is imported")
x = 'moduleA constant'
运行main.py
时,输出结果如下:
moduleA is imported
packageA is imported
moduleA constant
moduleA constant
总之:
__all__
变量控制from package import *
的行为
# 即使没有 __all__ 也可以访问
print(moduleA.模块A中的变量) # 可以正常输出(虽然能访问,但违反约定)
# 如果是通过 * 导入则无法访问
from packageA import *
print(moduleA中的变量) # NameError(如果 __init__.py 没有在 __all__ 中暴露)
- 当没有定义
__all__
时,只会导入__init__.py
中定义的名称 - 使用
__all__
可以明确暴露的模块/变量(推荐始终显式定义)
注意区别 from packageA.moduleA import x
与from packageA import x
有什么区别:
from packageA.moduleA import x
- 明确从 packageA 包的 moduleA 模块导入符号 x ** (会执行__init__.py中的代码,同时也会会执行moduleA中的代码)**
- 要求 moduleA 必须存在且包含 x 属性
- 导入路径: packageA → moduleA → x
from packageA import x
- 尝试直接从 packageA 包的
__init__.py
导入符号 x (只会执行__init__.py中的代码) - 需要
packageA/__init__.py
中存在 x 定义或显式导入(例如 from .moduleA import x ) - 若
__init__.py
未导出 x ,会引发 ImportError
- 尝试直接从 packageA 包的
- 包的信息,如作者、版本
# __init__.py
__version__ = "1.0.0"
__author__ = "Your Name"
__license__ = "MIT"
4. Python 3.3+ 的隐式命名空间包
从 Python 3.3 开始,即使没有 __init__.py
文件,目录也会被识别为包(称为 namespace package)。但显式创建 __init__.py
仍然是推荐做法:
- 支持传统包的明确初始化
- 更方便定义包级属性/方法
- 更好的IDE支持