entry_points 是 setuptools 提供的声明式插件注册机制,核心价值在于解耦:主程序不硬编码插件路径,插件也不需主动注册;它在安装时写入 entry_points.txt,运行时由 importlib.metadata 或 pkg_resources 读取,仅适用于已安装的包。

entry_points 是什么,为什么它能注册全局命令
entry_points 不是 Python 内置机制,而是 setuptools(或现代的 build 后端如 hatchling)在安装包时读取的配置项,用于声明“这个函数可以被当作命令行工具调用”。安装时,setuptools 会根据 console_scripts 这个 entry point 组,自动生成一个可执行脚本,放入 Python 环境的 bin/(macOS/Linux)或 Scripts\(Windows)目录,并自动添加 shebang 和模块导入逻辑。
关键点:它依赖 pip install -e . 或正式安装,不是运行时生效;不装包,mytool 命令就不存在。
setup.py vs pyproject.toml:怎么写 entry_points 才有效
现在主流用 pyproject.toml,但很多人照抄旧教程写 setup.py,结果在现代构建流程里被忽略——因为 PEP 517 规定,如果存在 pyproject.toml,setup.py 默认不被读取。
正确做法(pyproject.toml):
[project.entry-points."console_scripts"] mytool = "mytool.cli:main"
说明:
-
mytool是最终生成的命令名(用户敲mytool --help) -
mytool.cli:main是模块路径加函数名,格式为<package>.<module>:<function></function></module></package> - 冒号前必须是 importable 的 Python 模块路径,不能带
.py后缀 - 函数
main()必须接受零参数(或只处理sys.argv),且不应有if __name__ == "__main__":包裹——entry point 会直接调用它
常见报错:命令找不到、ModuleNotFoundError、AttributeError
装完包却提示 command not found 或 ImportError: No module named 'mytool',通常是因为:
- 没在当前 Python 环境中安装:确认
which mytool或where mytool是否指向虚拟环境路径;检查pip list | grep mytool - 模块路径写错:
mytool.cli:main要求mytool/__init__.py和mytool/cli.py都存在,且cli.py里定义了def main(): - 函数签名错误:如果
main()带了必需参数(比如def main(args)),调用时会报TypeError;应改用def main() -> None:,内部用argparse解析sys.argv[1:] - Windows 下权限问题:某些杀毒软件会拦截
Scripts\mytool.exe创建,可临时禁用或换用pip install --user
如何让 CLI 支持子命令和参数解析
entry_points 只负责把 main() 函数挂到命令行,真正的 CLI 体验靠你自己实现。别指望它自动支持 --help 或子命令——你得自己写。
推荐组合:
- 用
argparse(标准库)做基础参数解析,适合简单工具 - 用
click或typer声明式定义命令,它们天然适配 entry point:例如typer.Typer()实例的command()方法注册后,main()直接调用app()即可 - 避免在
main()里写太多逻辑:把它当作入口胶水函数,只做初始化、参数解析、分发,业务逻辑放别处
示例(mytool/cli.py):
import argparse
def main():
parser = argparse.ArgumentParser(prog="mytool")
parser.add_argument("--verbose", action="store_true")
args = parser.parse_args()
if args.verbose:
print("Running in verbose mode")
真正难的不是注册命令,而是让 main() 在不同平台、不同 Python 版本、不同安装方式(venv / conda / user install)下都稳定接收参数并退出正确状态码。这点容易被忽略,但直接影响工具是否“可用”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











