检查Python包是否已安装

178 投票
21 回答
332568 浏览
提问于 2025-04-15 12:31

在Python脚本中,有什么好的方法来检查一个包是否已经安装?我知道在解释器中很简单,但我需要在脚本里做这件事。

我想我可以检查系统中是否有一个在安装时创建的目录,但我觉得还有更好的方法。我想确认Skype4Py这个包是否已经安装,如果没有的话我就去安装它。

我想到的检查方法:

  • 检查常见安装路径下是否有一个目录
  • 尝试导入这个包,如果出现异常,那就安装这个包

21 个回答

68

更新的回答

更好的做法是:

import subprocess
import sys

reqs = subprocess.check_output([sys.executable, '-m', 'pip', 'freeze'])
installed_packages = [r.decode().split('==')[0] for r in reqs.split()]

结果是:

print(installed_packages)

[
    "Django",
    "six",
    "requests",
]

检查一下 requests 是否已经安装:

if 'requests' in installed_packages:
    # Do something

为什么要这样做?有时候应用的名字会重复。直接从应用的命名空间导入,可能无法全面了解系统上安装了哪些东西。

需要注意的是,下面提到的解决方案在以下情况下有效:

  • 当你使用 pip 从 PyPI 或其他替代源安装时(比如 pip install http://some.site/package-name.zip 或其他压缩包)。
  • 当你手动安装时,使用 python setup.py install
  • 当你从系统的仓库安装时,比如 sudo apt install python-requests

可能有效的情况:

  • 当你在开发模式下安装时,比如 python setup.py develop
  • 当你在开发模式下安装时,比如 pip install -e /path/to/package/source/

旧的回答

更好的做法是:

import pip
installed_packages = pip.get_installed_distributions()

对于 pip>=10.x,使用:

from pip._internal.utils.misc import get_installed_distributions

为什么要这样做?有时候应用的名字会重复。直接从应用的命名空间导入,可能无法全面了解系统上安装了哪些东西。

这样,你会得到一系列 pkg_resources.Distribution 对象。下面是一个例子:

print installed_packages
[
    "Django 1.6.4 (/path-to-your-env/lib/python2.7/site-packages)",
    "six 1.6.1 (/path-to-your-env/lib/python2.7/site-packages)",
    "requests 2.5.0 (/path-to-your-env/lib/python2.7/site-packages)",
]

把它们列成一个列表:

flat_installed_packages = [package.project_name for package in installed_packages]

[
    "Django",
    "six",
    "requests",
]

检查一下 requests 是否已经安装:

if 'requests' in flat_installed_packages:
    # Do something
100

从Python 3.3开始,你可以使用find_spec()这个方法。

import importlib.util

# For illustrative purposes.
package_name = 'pandas'

spec = importlib.util.find_spec(package_name)
if spec is None:
    print(package_name +" is not installed")
161

如果你指的是一个Python脚本,可以这样做:

在Python 3.3及以上版本中,可以使用sys.modules和find_spec

import importlib.util
import sys

# For illustrative purposes.
name = 'itertools'

if name in sys.modules:
    print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
    # If you choose to perform the actual import ...
    module = importlib.util.module_from_spec(spec)
    sys.modules[name] = module
    spec.loader.exec_module(module)
    print(f"{name!r} has been imported")
else:
    print(f"can't find the {name!r} module")

在Python 3中:

try:
    import mymodule
except ImportError as e:
    pass  # module doesn't exist, deal with it.

在Python 2中:

try:
    import mymodule
except ImportError, e:
    pass  # module doesn't exist, deal with it.

撰写回答