检查Python包是否已安装
在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.