核心区别
| 特性 | __init__.py | main.py/__main__.py |
|---|---|---|
| 角色 | 包初始化与暴露 API | 项目执行与入口点 |
| 触发时机 | 当你 import 目录时自动触发 | 通过 CLI 手动运行( python main.py ) |
| 典型内容 | 干净的 API 导出;初始化配置 | 编排逻辑,CLI 解析,启动应用 |
__init__.py:包管理器
__init__.py 文件告诉 Python 应将一个目录视为常规包。当有人导入(import)你的目录时,这个文件会在后台自动执行。
- 初始化代码:它设置包级别的变量或连接池。
- 暴露更干净的 API:你无需强迫用户输入
from mypackage.module.submodule import MyClass,可以直接在__init__.py中导入MyClass。用户随后可以编写from mypackage import MyClass。 - 定义包范围:您可以在其中使用
__all__变量来控制在通配符(from package import *)操作期间暴露的内容。
一个例子
项目结构
my_project/
└── my_package/
├── __init__.py # 包的初始化文件
├── core.py # 核心业务逻辑模块
└── utils.py # 工具函数模块编写核心业务函数:my_package/core.py
def calculate_score(data):
return sum(data) * 1.5编写常用的工具函数:my_package/utils.py
def format_date(timestamp):
return f"Date: {timestamp}"在初始化文件中,将两个模块的函数暴露到“包级别”
# 1. 定义包级别的全局变量
__version__ = "1.0.0"
AUTHOR = "Developer"
# 2. 预先导入子模块中的函数(提升到包的顶级命名空间)
from .core import calculate_score
from .utils import format_date
# 3. 显式定义允许导出的内容(可选,但推荐)
__all__ = ["calculate_score", "format_date", "__version__"]
如果__init__.py 为空,调用者必须知道具体的文件名,路径较深
from my_package.core import calculate_score
from my_package.utils import format_date
print(calculate_score([1, 2, 3]))如果配置了 __init__.py,调用者无需关心函数具体在哪个隐藏的文件里,直接从包导入
# 一行搞定所有导入
from my_package import calculate_score, format_date, __version__
print(__version__) # 输出: 1.0.0
print(calculate_score([1, 2, 3])) # 输出: 9.0main.py 与 __main__.py:项目执行入口
这些文件旨在启动应用程序运行时。
main.py:这是典型应用程序存储库中项目执行文件的标准命名约定。通过明确指向它来执行它:python main.py。__main__.py: 这是一个特殊内部文件,用于当你想将整个包作为脚本运行时执行。运行python -m mypackage会告诉 Python 在包文件夹内查找并自动执行__main__.py。
示例项目结构
这是它们在应用程序中并排工作时的一般外观:
my_project/
│
├── main.py # Application entry point (runs the whole app)
└── my_package/ # An importable directory package
├── __init__.py # Executes on `import my_package`
├── __main__.py # Executes on `python -m my_package`
├── database.py
└── utils.py
总结
- 除非你想让它在每次有人从那个文件夹导入东西时都运行,否则不要在
__init__.py中包含代码。 - 将
__init__.py中的初始化逻辑保持轻量。 - 将脚本执行代码严格保持在
main.py或__main__.py内。