Python代码中怎么获取第三方库版本号

听雨眠
听雨眠
发布时间:2026-11-03| 7人浏览过
原创

全面解析在Python代码中获取第三方库版本号的标准方法与实用技巧,涵盖内置importlib.metadata、__version__属性读取、分发包名与导入名映射避坑及批量获取方案。

类型:Python 核心语法与标准库 环境:Python 3.8 及以上(兼容旧版本)
在 Python 脚本或应用程序中获取已安装第三方库的版本号,最稳健的标准方案是调用 Python 3.8+ 标准库内置的 importlib.metadata.version("包名"),其最大优势在于无需实际导入第三方模块即可直接提取版本;若目标库已经被业务代码导入,也可以通过访问该模块约定的 __version__ 属性获取。理解这两种机制的工作原理、分发包名与导入模块名的差异,以及相应的异常防御策略,是确保环境检测与依赖管理代码高可用性的核心关键。
Python代码中怎么获取第三方库版本号
图 0:Python 库版本号提取技术导览与核心方案

一、现代标准方式:使用 importlib.metadata.version()

自 Python 3.8 起,官方在标准库中引入了 importlib.metadata 模块(遵循 PEP 566 规范),用于取代过去依赖外部 setuptools 工具包的旧模式。该模块直接通过操作系统文件检索已安装发行包的元数据清单(.dist-info 目录),因此无需加载 Python 模块本身。

1. 基本用法示例

以查询常见的网络请求库 requests 为例,直接在代码中调用 version() 函数:

from importlib import metadata

# 传入安装时使用的发行包名(不区分大小写)
pkg_version = metadata.version("requests")
print(f"requests 当前版本为: {pkg_version}")
控制台运行示例输出:
requests 当前版本为: 2.31.0

2. 免导入解析的核心优势

如果使用传统的 import 方式来读取版本,Python 解释器必须把该模块完整的 __init__.py 及关联依赖全部装入内存。对于像 torch、tensorflow、pandas 这类大型科学计算库,导入耗时往往在数百毫秒到数秒之间,甚至可能触发 GPU 驱动初始化或占用大量内存。而 metadata.version() 仅进行轻量级的元数据文件读取,执行耗时通常在毫秒以内,非常适合在启动前健康检查、日志标记或依赖自检逻辑中使用。

3. 异常防御:处理 PackageNotFoundError

当查询的环境中未安装该库,或者传入的名称有拼写错误时,metadata.version() 会抛出 importlib.metadata.PackageNotFoundError。在工程代码中,应当始终包裹异常捕获块:

from importlib import metadata

def get_installed_version(distribution_name: str) -> str:
    try:
        return metadata.version(distribution_name)
    except metadata.PackageNotFoundError:
        return "未安装或包名不存在"

print(get_installed_version("numpy"))
print(get_installed_version("non_existent_package_xyz"))
控制台运行示例输出:
1.26.4
未安装或包名不存在
Python代码中怎么获取第三方库版本号
图 1:importlib.metadata.version 调用步骤与异常防御执行链路

二、传统属性方式:读取模块的 __version__ 属性

在 Python 社区中,PEP 396 曾提倡模块作者在包顶层命名空间暴露一个名为 __version__ 的字符串变量。如果你正在编写的业务代码已经执行了 import package_name,那么直接读取该属性是最自然的做法。

1. 基本用法与模块属性读取

以 urllib3 和 pandas 为例:

import urllib3
import pandas as pd

# 直接访问模块顶层属性
print(f"urllib3 版本: {urllib3.__version__}")
print(f"pandas 版本: {pd.__version__}")
控制台运行示例输出:
urllib3 版本: 2.2.1
pandas 版本: 2.2.2

2. 注意事项与局限性

依赖 __version__ 属性需要注意两个前提约束:

  • 非强制性约定:PEP 396 是一项历史性建议,并非语言层面的语法规范。少数第三方库(特别是通过 C/C++ 绑定的扩展模块,或部分轻量级内部工具库)并没有在 __init__.py 中定义此属性,直接读取将引发 AttributeError。
  • 导入副作用:必须保证代码环境满足该库导入的全部依赖项,否则在 import 阶段就会提前触发 ModuleNotFoundError 或 ImportError。

为了防止属性不存在导致程序崩溃,推荐使用内置的 getattr() 函数提供默认值:

import some_library

# 安全获取,不存在时返回默认占位值
ver = getattr(some_library, "__version__", "未知版本")
Python代码中怎么获取第三方库版本号
图 2:importlib.metadata 静态解析与 __version__ 动态导入机制对比

三、关键避坑点:分发包名与导入模块名的差异

在实际开发中,导致版本获取失败的最常见原因之一,是混淆了“分发包名(Distribution Name)”与“导入模块名(Import Name)”。

在 PyPI 仓库中注册并供 pip install 下载的名称是分发包名;而在 Python 代码中 import 的则是包作者在源码顶级目录中声明的模块标识符。这两者在相当多的主流库中并不一致:

  • YAML 解析库:安装命令为 pip install PyYAML,但在代码中导入为 import yaml。若执行 metadata.version("yaml") 会直接抛出 PackageNotFoundError,正确的调用是 metadata.version("PyYAML")。
  • 机器学习库 Scikit-Learn:安装命令为 pip install scikit-learn,代码中为 import sklearn。查询元数据必须用 metadata.version("scikit-learn")。
  • 图像处理库 Pillow:安装命令为 pip install Pillow,代码中为 from PIL import Image。元数据查询应传入 "Pillow"。
  • 网页解析库 BeautifulSoup:安装为 pip install beautifulsoup4,导入为 import bs4。
Python代码中怎么获取第三方库版本号
图 3:常见第三方库分发包名与导入模块名对照及映射原理

针对这一差异,如果你编写的公共工具函数只接收模块对象或字符串,建议建立兼容回退映射,或在顶层设计中明确区分参数含义:

from importlib import metadata

# 建立已知差异别名表
NAME_MAP = {
    "yaml": "PyYAML",
    "sklearn": "scikit-learn",
    "PIL": "Pillow",
    "bs4": "beautifulsoup4",
    "cv2": "opencv-python",
}

def query_library_version(name: str) -> str:
    # 优先尝试原始名称
    dist_name = NAME_MAP.get(name, name)
    try:
        return metadata.version(dist_name)
    except metadata.PackageNotFoundError:
        # 尝试备选名称
        alt_name = NAME_MAP.get(name.lower(), name)
        try:
            return metadata.version(alt_name)
        except metadata.PackageNotFoundError:
            return "未找到对应分发包"

print("PyYAML 查询结果:", query_library_version("yaml"))
print("Pillow 查询结果:", query_library_version("PIL"))
控制台运行示例输出:
PyYAML 查询结果: 6.0.1
Pillow 查询结果: 10.3.0

四、历史方案与全量依赖自省

1. 为什么不再推荐 pkg_resources?

在很多旧项目或早期教程中,经常能看到如下写法:

# 旧版代码(不推荐)
import pkg_resources
version = pkg_resources.get_distribution("requests").version

虽然该方法功能完整,但在现代 Python 环境中已不建议使用。pkg_resources 隶属于 setuptools,不仅在导入时需要扫描整个 sys.path 带来显著的启动延迟,而且在 Python 3.12 及更高版本中,官方已将其标记为废弃(Deprecated)。新项目与维护升级中应一律切换为 importlib.metadata。

2. 在代码中批量列出所有已安装库及其版本

若你的程序需要生成运行时环境报告或诊断日志,可以使用 importlib.metadata.distributions() 一次性遍历当前 Python 环境中的全部第三方包:

from importlib import metadata

def list_all_packages():
    installed_packages = {}
    for dist in metadata.distributions():
        name = dist.metadata["Name"]
        version = dist.version
        installed_packages[name] = version
    return installed_packages

# 打印前 5 个包信息作为演示
packages = list_all_packages()
for name in list(packages.keys())[:5]:
    print(f"{name}: {packages[name]}")
控制台运行示例输出:
pip: 24.0
setuptools: 69.5.1
wheel: 0.43.0
requests: 2.31.0
urllib3: 2.2.1
Python代码中怎么获取第三方库版本号
图 4:Python 第三方库版本获取技术选型与回退决策树

五、总结与选择建议

总结在 Python 代码中获取第三方库版本号的工程实践路径:

  1. 优先标准库:在 Python 3.8+ 环境下,无特殊理由均推荐首选 importlib.metadata.version("包名")。它兼具零模块导入开销、官方长期维护保障与标准化异常机制。
  2. 顺带读取:当且仅当该模块本身已经进入核心执行路径且必然会被导入时,直接读取 getattr(pkg, "__version__", None) 可以作为快捷补充。
  3. 注意入参一致性:牢记 importlib.metadata.version 需要传入 pip 安装时声明的分发包名(如 PyYAML),而非业务代码里的模块名(如 yaml)。
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。