怎么在Python代码中获取已安装包的列表

Evan
Evan
发布时间:2026-11-11| 5人浏览过
原创

详细讲解在Python代码中如何获取当前环境中所有已安装包的名称与版本号。涵盖现代标准库importlib.metadata的完整用法、底层.dist-info元数据发现原理、subprocess与pkg_resources方案对比及避坑指南。

适用版本:Python 3.8+ (全平台适用) 运行环境:标准 CPython 解释器及虚拟环境 核心模块:importlib.metadata
怎么在Python代码中获取已安装包的列表
图 1:Python 代码内获取已安装包核心方案架构概览
在 Python 代码中获取已安装包清单最标准、高效的方法是使用 Python 3.8 原生内置的 importlib.metadata 标准库。只需调用 importlib.metadata.distributions(),即可直接遍历当前运行环境中所有分发包的名称与版本号,整个过程在 Python 进程内完成,无需启动子进程,也不依赖任何外部第三方工具库。

一、首选方案:使用标准库 importlib.metadata

在过去,很多开发者习惯通过调用外部命令行或者导入 pkg_resources 来查看安装环境。自 Python 3.8 起,官方引入了标准库 importlib.metadata(基于 PEP 566 与 PEP 592),正式取代了以往非标准或开销巨大的方案。

1. 获取全量包名与版本清单

以下是直接在 Python 代码中获取所有已安装包名称及对应版本的标准写法:

import importlib.metadata

# 获取当前环境中所有分发包的迭代器
dists = importlib.metadata.distributions()

# 按包名不区分大小写排序并打印
installed_packages = []
for dist in dists:
    name = dist.metadata['Name']
    version = dist.version
    installed_packages.append((name, version))

installed_packages.sort(key=lambda x: x[0].lower())

for name, ver in installed_packages:
    print(f"{name} == {ver}")
示例输出(实际结果根据本地环境各异) certifi == 2024.7.4
charset-normalizer == 3.3.2
idna == 3.7
pip == 24.1.2
requests == 2.32.3
urllib3 == 2.2.2

在这段代码中,distributions() 返回一个由 Distribution 对象构成的可迭代集合。每个对象包含了该包完整的元数据,其中 dist.metadata['Name'] 是包在 Python 官方包索引(PyPI)注册的正式分发名称,而 dist.version 则是已安装的具体版本号。

版本兼容性细节(Python 3.10+)

在 Python 3.10 及以上版本中,Distribution 对象新增了直接属性 dist.name,无需通过字典下标 dist.metadata['Name'] 即可获取名称。如果代码需要同时兼顾 Python 3.8、3.9 与 3.10+,推荐使用 getattr(dist, 'name', None) or dist.metadata['Name'] 进行兼容读取。

怎么在Python代码中获取已安装包的列表
图 2:importlib.metadata 提取已安装包元数据的步骤执行流

二、底层机制:Python 如何识别“已安装包”

很多初学者容易将“已安装的包”与“已载入内存的模块”混淆,误以为从 sys.modules 中就能检索出所有包。理解 Python 的包发现机制,有助于我们在代码中写出更健壮的环境自检逻辑。

当执行 pip install 安装第三方库时,pip 会将两个核心要素写入 Python 解释器的 site-packages 目录:

  • 代码目录/模块文件:包含实际运行 Python 代码的文件夹(例如 requests/)。
  • 分发元数据目录:以 .dist-info 结尾的文件夹(例如 requests-2.32.3.dist-info/)。该目录下包含标准文本文件 METADATA,详细记录了包名、版本、依赖列表、平台架构等信息。

importlib.metadata.distributions() 的执行本质,就是按照 sys.path 包含的路径列表,在所有搜索路径下扫描存在的 *.dist-info 和 *.egg-info 目录,并解析其中的 METADATA 描述文件。它完全不需要将包的代码导入到内存中,因此执行速度极快(通常在 10 到 30 毫秒以内),且绝不会触发第三方包顶层模块中可能包含的副作用代码。

怎么在Python代码中获取已安装包的列表
图 3:site-packages 物理元数据与运行时内存的架构差异
警惕“分发包名”与“导入模块名”的不一致

在 Python 生态中,分发包名称(Distribution Name)与实际在代码中 import 的模块名并不总是一致:

  • 分发包名为 PyYAML,但在代码中导入的是 import yaml。
  • 分发包名为 Pillow,但在代码中导入的是 import PIL。
  • 分发包名为 opencv-python,但在代码中导入的是 import cv2。

distributions() 获取的是分发包的名字与版本。若需要在代码中根据用户 import 的顶层模块名反查其所属分发包,Python 3.10+ 提供了 importlib.metadata.packages_distributions():

# Python 3.10+ 内置反查映射
mapping = importlib.metadata.packages_distributions()
print(mapping.get('PIL'))   # 输出: ['Pillow']
print(mapping.get('yaml'))  # 输出: ['PyYAML']

三、方案对比:importlib.metadata、subprocess 与 pkg_resources

在实际项目和历史代码库中,我们可能会见到多种获取包列表的手法。了解它们的区别有助于根据实际业务场景做出合理的工程选型。

怎么在Python代码中获取已安装包的列表
图 4:三大方案技术对比与工程选型决策路径

1. 备选方案:通过 subprocess 调用 pip list(JSON 格式)

如果你的需求是获取绝对与当前环境命令行下 pip list 完全一致的输出,或者需要检查外部某个指定路径的 Python 解释器环境,可以使用 subprocess:

import json
import subprocess
import sys

def get_installed_via_pip():
    # 使用 sys.executable 确保调用的是当前正在运行的解释器对应的 pip
    cmd = [sys.executable, "-m", "pip", "list", "--format=json"]
    result = subprocess.run(cmd, capture_output=True, text=True, check=True)
    return json.loads(result.stdout)

packages = get_installed_via_pip()
for item in packages:
    print(f"{item['name']} : {item['version']}")

适用场景与代价:该方案的好处是格式由 pip 统一保障,并且天然支持 --editable 或外部环境隔离;缺点是每次调用都需要启动一个全新的操作系统子进程,耗时通常在 200~500 毫秒以上。此外,如果生产环境出于精简目的卸载了 pip(例如部分最小化 Docker 镜像),该调用会直接报错。

2. 历史方案:pkg_resources(已弃用,不建议新项目使用)

在老旧的 Python 教程中经常看到如下代码:

# 不推荐在新项目中继续使用
import pkg_resources

installed = {pkg.key: pkg.version for pkg in pkg_resources.working_set}

为什么必须淘汰:pkg_resources 属于 setuptools 的一部分。在较新的 setuptools 版本中,官方已明确将其标记为 Deprecated(弃用)。导入 pkg_resources 时会深度扫描所有环境并构建复杂的运行时依赖图,不仅显著拖慢 Python 程序的启动时间,还会触发弃用告警。所有现有项目均应逐步迁移至 importlib.metadata。

四、进阶实用场景与代码实现

1. 快速检查单个包是否安装及获取版本

如果仅需检测某个具体包是否存在,无需遍历全量列表,直接调用 version() 函数即可。注意未安装时会抛出 PackageNotFoundError:

import importlib.metadata

def check_package_version(package_name: str):
    try:
        ver = importlib.metadata.version(package_name)
        return ver
    except importlib.metadata.PackageNotFoundError:
        return None

version = check_package_version("requests")
if version:
    print(f"requests 已安装,版本为 {version}")
else:
    print("requests 尚未安装")

2. 获取指定包声明的依赖项

通过 requires() 可以读取指定包在打包时声明的下游依赖要求(包括版本限制与条件标记):

import importlib.metadata

reqs = importlib.metadata.requires("requests")
if reqs:
    for r in reqs:
        print(r)
示例输出(requests 包所声明的依赖要求) charset-normalizer<4,>=2
idna<4,>=2.5
urllib3<3,>=1.21.1
certifi>=2017.4.17

3. 生成环境包依赖字典(用于系统诊断或上报)

如果需要在服务启动时收集诊断指标,可以将已安装包整理为规整的键值字典:

import importlib.metadata

def get_installed_packages_dict():
    pkg_dict = {}
    for dist in importlib.metadata.distributions():
        name = getattr(dist, 'name', None) or dist.metadata['Name']
        # 按照 PEP 503 规范将下划线统一为中划线并转小写,避免命名差异
        normalized_name = name.lower().replace("_", "-")
        pkg_dict[normalized_name] = dist.version
    return pkg_dict

env_summary = get_installed_packages_dict()
print(f"当前共安装 {len(env_summary)} 个分发包")
怎么在Python代码中获取已安装包的列表
图 5:工程化实践与健壮性避坑指南总结

五、工程实践常见问题与注意事项

  1. 虚拟环境感知:Python 代码检测的包列表始终与当前正在运行的 Python 解释器(sys.executable)保持一致。如果你在激活了 Virtualenv 或 Conda 的环境中运行脚本,获取到的就是该虚拟环境的独立包列表;若在多解释器服务器上部署,需确保启动脚本使用的是目标虚拟环境的 Python 路径。
  2. 以可编辑模式(Editable / pip install -e .)安装的本地开发包:现代 pip 支持 PEP 660 可编辑安装标准,会在 site-packages 下生成包含 __editable__.*.pth 或 .dist-info 元数据,importlib.metadata.distributions() 同样能够准确检索并返回其版本号与名称。
  3. Python 3.7 环境下的后向兼容:如果必须在已停止支持的 Python 3.7 上运行,可以通过 pip install importlib-metadata 安装官方 backport 库,然后在代码中使用 import importlib_metadata as metadata,其 API 与现代 Python 内置标准库完全一致。

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

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 算法库。