检查是否安装了Python软件包


112

检查软件包是否在Python脚本中安装的好方法是什么?我知道从解释器很容易,但是我需要在脚本中完成。

我想我可以检查安装过程中在系统上是否创建了目录,但是我觉得有更好的方法。我试图确保已安装Skype4Py软件包,如果没有,我将安装它。

我完成支票的想法

  • 检查典型安装路径中的目录
  • 尝试导入软件包,如果抛出异常,则安装软件包

编写Python脚本来自动启动Skype,并使用tcpdump收集数据包数据,以便在您进行电话会议时分析网络的运行方式。
凯文

Answers:


106

如果您的意思是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.

6
警告:今天我只是遇到了一个错误,其中ImportError被抛出到模块本身中。这种情况不应该经常发生,但要注意,这种检查在所有情况下都不可靠。
Koen Bok

7
这不仅检查 ; 它还导入它;又见stackoverflow.com/questions/14050281/...
乔奇·莱塔

6
是。通常这就是您想要的。您可以使用导入工具模块进行更复杂的检查,但是大多数情况下,您唯一关心是否安装模块的原因是您要使用它。
Christopher

如果您有另一个与包同名的文件,则此操作将失败。
Sapphire_Brick

当然,但这是一个完全不同的问题。如果您在查找路径中有两个具有相同名称的不同模块或软件包,那么您会遇到麻烦。
克里斯托弗

56

更新的答案

更好的方法是:

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

2
如另一个答案中所述,有可能未捕获到错误。因此,我认为这应该是公认的答案。
乔里克·斯莱斯特

1
此方法不适用于'json'之类的软件包(在import json确实有效时返回False )。ice.nicer的方法在这种情况下有效。
mountrix

1
我不知何故需要使用“ if "u'requests'" in installed_packages:更新的答案”中的检查为我工作。print()在我的macOS python上产生以下命令的输出:[..., u'pytz', u'requests', ...]
Buju

1
@ArturBarseghyan我正在使用Python 2.7.10(macOS系统python)...实际上我必须使用if "requests'"(注意最后的单引号)。完全没有意义。
Buju

1
这不能回答以下问题:“是否安装了软件包'x'?”。有许多不使用而安装软件包的方法pip。例如,您可以从源代码制作和安装软件包。这个答案找不到那些。@ ice.nicer的答案find_spec()是正确的。
亚瑟

43

从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")

4
干净简单,最好的答案在这里。这需要更多的投票。
David Parks

5
小心。如果程序包名称包含破折号,则除非使用点,否则find_spec()找不到它。示例:在importlib.util.find_spec('google-cloud-logging')找到时什么importlib.util.find_spec('google.cloud.logging')也找不到。点子显示的正式名称和名称用短划线而不是点号表示。可能会造成混淆,因此请谨慎使用。
dwich

27

如果要从终端机取支票,可以运行

pip3 show package_name

如果未返回任何内容,则表示未安装该软件包。

如果您想自动执行此检查,以便例如可以在丢失时安装它,则可以在bash脚本中包含以下内容:

pip3 show package_name 1>/dev/null #pip for Python 2
if [ $? == 0 ]; then
   echo "Installed" #Replace with your actions
else
   echo "Not Installed" #Replace with your actions, 'pip3 install --upgrade package_name' ?
fi

这看起来很棒,但它总是为我返回“未安装”。为什么?
Elliptica

您可以共享“ $ pip3 -version”和“ $ pip3 show package_name”的输出,在其中用所需的软件包替换package_name吗?
Ognjen Vukovic

Shell提示:您可以if用来直接测试成功的命令:if pip3 show package_name 1>/dev/null; then ...
MestreLion

6

作为此答案的扩展:

对于Python 2. *,pip show <package_name>将执行相同的任务。

例如pip show numpy将返回以下内容:

Name: numpy
Version: 1.11.1
Summary: NumPy: array processing for numbers, strings, records, and objects.
Home-page: http://www.numpy.org
Author: NumPy Developers
Author-email: numpy-discussion@scipy.org
License: BSD
Location: /home/***/anaconda2/lib/python2.7/site-packages
Requires: 
Required-by: smop, pandas, tables, spectrum, seaborn, patsy, odo, numpy-stl, numba, nfft, netCDF4, MDAnalysis, matplotlib, h5py, GridDataFormats, dynd, datashape, Bottleneck, blaze, astropy

不是来自脚本,而是用于命令行检查。谢谢
Jj Rivero

3

您可以使用setuptools中的pkg_resources模块。例如:

import pkg_resources

package_name = 'cool_package'
try:
    cool_package_dist_info = pkg_resources.get_distribution(package_name)
except pkg_resources.DistributionNotFound:
    print('{} not installed'.format(package_name))
else:
    print(cool_package_dist_info)

请注意,python模块和python包之间有区别。一个软件包可以包含多个模块,并且模块名称可能与软件包名称不匹配。



1

我想对此主题添加一些想法/发现。我正在编写一个脚本,检查定制程序的所有要求。python模块也有很多检查。

有一个小问题

try:
   import ..
except:
   ..

解。在我的情况下,其中一个python模块称为python-nmap,但是您使用导入了它,import nmap并且看到名称不匹配。因此,使用上述解决方案进行的测试将返回False结果,并且还会在命中时导入该模块,但对于简单的测试/检查,可能无需使用大量内存。

我也发现

import pip
installed_packages = pip.get_installed_distributions()

installed_packages只有pip安装了软件包。在我的系统上,pip freeze通过40python模块返回,而installed_packages只有1,我手动安装了该模块(python-nmap)。

下面我知道的另一种解决方案可能与该问题无关,但是我认为将测试功能与执行安装的功能分开是一种很好的做法,这可能对某些人有用。

对我有用的解决方案。它基于此答案如何在不导入的情况下检查python模块是否存在

from imp import find_module

def checkPythonmod(mod):
    try:
        op = find_module(mod)
        return True
    except ImportError:
        return False

注意:此解决方案也无法通过名称找到模块python-nmap,我必须nmap改用(易于使用),但是在这种情况下,模块将不会加载到内存中。


0

如果您希望脚本安装缺少的软件包并继续,则可以执行以下操作(在“ python-krbV”软件包中的“ krbV”模块示例中):

import pip
import sys

for m, pkg in [('krbV', 'python-krbV')]:
    try:
        setattr(sys.modules[__name__], m, __import__(m))
    except ImportError:
        pip.main(['install', pkg])
        setattr(sys.modules[__name__], m, __import__(m))

0

一种快速的方法是使用python命令行工具。只需键入,import <your module name> 如果缺少模块,则会看到错误。

$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
>>> import sys
>>> import jocker
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named jocker
$

0

嗯...我看到的最方便的答案是使用命令行尝试导入。但我什至宁愿避免这种情况。

冻结点如何?grep pkgname'?我试过了,效果很好。它还显示了它具有的版本以及是在版本控制(安装)下还是可编辑(开发)下安装的。


0

类myError(exception):通过#或做一些尝试:导入mymodule,除了ImportError,例如e:提高myError(“发生错误”)


0

在终端类型

pip show some_package_name

pip show matplotlib

0

我想评论@ ice.nicer的回复,但我不能,所以... 我的观察是带有破折号的软件包都带有下划线,而不仅仅是@dwich注释所指出的点。

例如,您这样做pip3 install sphinx-rtd-theme,但是:

  • importlib.util.find_spec(sphinx_rtd_theme) 返回一个对象
  • importlib.util.find_spec(sphinx-rtd-theme) 不返回
  • importlib.util.find_spec(sphinx.rtd.theme) 引发ModuleNotFoundError

此外,某些名称已完全更改。例如,您这样做,pip3 install pyyaml但是将其另存为yaml

我正在使用python3.8


0
if pip3 list | grep -sE '^some_command\s+[0-9]' >/dev/null
  # installed ...
else
  # not installed ...
fi

-1

转到选项2。如果ImportError抛出该错误,则表示未安装该软件包(或未安装sys.path)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.