Python 3.10+ 可直接用 importlib.metadata 读取已安装包元数据,metadata() 获取完整信息,version() 快速获取版本;需捕获 metadata.PackageNotFoundError 而非 ImportError;packages_distributions() 查导入名映射,entry_points() 查命令行入口;读自身版本时应优先解析 pyproject.toml。

直接用 importlib.metadata 读取已安装包的元数据
Python 3.10 开始,importlib.metadata 是标准库模块,不再需要额外装 importlib-metadata 包(那个是为旧版本提供的 backport)。只要包已通过 pip install 安装且有合规的 dist-info 或 egg-info 目录,就能直接查。
最常用的是 importlib.metadata.metadata() 和 importlib.metadata.version():
-
metadata("requests")返回一个Mapping对象,键如"Name"、"Summary"、"Author"、"Requires-Dist"—— 注意键名是 PEP 566 定义的,首字母大写,不是小写的"name" -
version("numpy")最快获取版本号,底层不解析整个 METADATA 文件,比metadata(...).get("Version")更轻量 - 如果包没安装或名字拼错,会抛出
importlib.metadata.PackageNotFoundError,不是ImportError,捕获时别写错
处理 PackageNotFoundError 的实际写法
线上服务或 CLI 工具里不能让异常崩掉流程,得兜底。常见错误是直接 try/except ImportError,但这是错的 —— PackageNotFoundError 继承自 Exception,和 ImportError 无关。
正确做法:
立即学习“Python免费学习笔记(深入)”;
from importlib import metadata
try:
ver = metadata.version("click")
except metadata.PackageNotFoundError:
ver = "unknown"
注意:metadata.PackageNotFoundError 在 Python 3.12 中被移到了 importlib.metadata 下的同名异常,但 3.10/3.11 仍需从 importlib.metadata 导入,不能从 importlib 直接导。
区分 packages_distributions() 和 entry_points() 的用途
这两个函数容易混淆,但职责完全不同:
-
packages_distributions()返回一个 dict,比如{"zipp": ["importlib-resources"]},表示哪些已安装包提供了某个顶层 import 名 —— 主要用于调试导入冲突或定位包来源 -
entry_points(group="console_scripts")返回EntryPoints对象,用来查setup.py或pyproject.toml里声明的命令行入口,比如black、flake8的可执行名 - 两者都不接受模糊匹配;
entry_points()在 Python 3.10 中默认只返回当前环境的入口点,不跨环境(如 venv 外的全局 site-packages),除非显式传include_missing=False并手动指定路径
在打包工具或 CI 中读取当前项目自身元数据的坑
想在自己项目的代码里读取自己的版本(比如 __version__),别直接用 metadata.version("myproject") —— 如果项目还没 install(比如开发中用 pip install -e .),可能读不到,尤其用 PEP 517 构建时,pyproject.toml 里的 dynamic 字段会导致 dist-info 缺失。
更稳的方式:
- 开发期:优先读
pyproject.toml的[project.version](用tomllib解析) - 发布后:再 fallback 到
metadata.version("myproject") - 绝对不要在
setup.py里调用metadata读自己 —— 此时dist-info还没生成,必然失败
动态版本号、editable install、PEP 621 项目结构会让 importlib.metadata 行为变复杂,这时候别只盯着一个 API 用到底。


















