在 Python 中,包(目录)下的
__main__.py文件有着非常明确且特殊的含义:**它允许你将一个 Python 包(Package)当作一个独立的脚本直接在命令行中运行。**简单来说,它是包的“执行入口”。
简介
- 它是什么:包的命令行入口点。
- 怎么用:
python -m 你的包名。 - 适用场景:当你写了一个库(如
cisctl),既想让别人在代码里import cisctl使用,又想提供一个命令行工具供人在终端直接敲击使用时,提供__main__.py是最优雅的做法。
核心作用:响应 python -m 命令
当使用 python -m 包名 这种方式运行代码时,Python 解释器会去该包的目录下寻找 __main__.py 文件,并把里面的代码当作主程序执行。
示例: 假设你有这样一个目录结构:
my_package/
├── __init__.py
├── core.py
└── __main__.py- 如果你执行:
python -m my_package - Python 就会自动找到并执行
my_package/__main__.py。
__main__.py vs __init__.py 的区别
__init__.py是“导入”入口: 当你在代码中写import my_package时,Python 执行的是__init__.py。它用于初始化包、暴露 API。__main__.py是“执行”入口: 当你在命令行写python -m my_package时,Python 执行的是__main__.py。它用于提供命令行工具(CLI)。
日常生活中的经典例子
其实已经使用过无数次包含 __main__.py 的内置包了:
- 启动本地 Web 服务:
(原理:Python 执行了自带
bashpython -m http.server 8000http包下的server模块,或者如果有个大包,执行其__main__.py)。 - 使用 pip 安装包:
(原理:
bashpython -m pip install requestspip是一个包,执行这条命令实际上是触发了pip/__main__.py)。 - 创建虚拟环境:
(原理:执行了自带
bashpython -m venv myenvvenv包下的__main__.py)。
为什么要用 __main__.py
- 避免暴露长路径:如果你的包里有一个执行脚本,用户不需要知道脚本藏在哪个很深的目录(例如
python /usr/lib/python3.10/site-packages/my_package/cli.py),只需优雅地敲python -m my_package即可。 - 确保在当前的 Python 环境运行:使用
python -m pip比直接敲pip更安全,因为它能 100% 确保使用的是你当前敲击的python对应的pip,避免系统环境变量混乱导致装错地方。 - 制作可执行的 ZIP 包:如果你把包含
__main__.py的目录打包成.zip或.pyz(Python Zip 格式),你可以直接运行这个压缩包:Python 会自动解压并在内存中执行压缩包内的 bashpython my_package.zip__main__.py!
如何写一个 __main__.py?
通常,__main__.py 的代码非常简单,它只负责接收命令行参数,然后调用包内其他模块的核心逻辑:
# my_package/__main__.py
import sys
from .core import main_logic # 从包的其他文件导入核心逻辑
def main():
print("Welcome to My Package CLI!")
args = sys.argv[1:]
# 处理参数并执行
main_logic(args)
if __name__ == "__main__":
main()注:虽然文件本身就是 __main__.py,但加上 if __name__ == "__main__": 依然是一个好习惯,防止它被意外 import 时直接执行。