检查是否安装了Python软件包

问题:检查是否安装了Python软件包

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

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

我完成支票的想法

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

What’s a good way to check if a package is installed while within a Python script? I know it’s easy from the interpreter, but I need to do it within a script.

I guess I could check if there’s a directory on the system that’s created during the installation, but I feel like there’s a better way. I’m trying to make sure the Skype4Py package is installed, and if not I’ll install it.

My ideas for accomplishing the check

  • check for a directory in the typical install path
  • try to import the package and if an exception is throw, then install package

回答 0

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

If you mean a python script, just do something like this:

Python 3.3+ use sys.modules and 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.

回答 1

更新的答案

更好的方法是:

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

Updated answer

A better way of doing this is:

import subprocess
import sys

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

The result:

print(installed_packages)

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

Check if requests is installed:

if 'requests' in installed_packages:
    # Do something

Why this way? Sometimes you have app name collisions. Importing from the app namespace doesn’t give you the full picture of what’s installed on the system.

Note, that proposed solution works:

  • When using pip to install from PyPI or from any other alternative source (like pip install http://some.site/package-name.zip or any other archive type).
  • When installing manually using python setup.py install.
  • When installing from system repositories, like sudo apt install python-requests.

Cases when it might not work:

  • When installing in development mode, like python setup.py develop.
  • When installing in development mode, like pip install -e /path/to/package/source/.

Old answer

A better way of doing this is:

import pip
installed_packages = pip.get_installed_distributions()

For pip>=10.x use:

from pip._internal.utils.misc import get_installed_distributions

Why this way? Sometimes you have app name collisions. Importing from the app namespace doesn’t give you the full picture of what’s installed on the system.

As a result, you get a list of pkg_resources.Distribution objects. See the following as an example:

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)",
]

Make a list of it:

flat_installed_packages = [package.project_name for package in installed_packages]

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

Check if requests is installed:

if 'requests' in flat_installed_packages:
    # Do something

回答 2

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

As of Python 3.3, you can use the find_spec() method

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

回答 3

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

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

If you want to have the check from the terminal, you can run

pip3 show package_name

and if nothing is returned, the package is not installed.

If perhaps you want to automate this check, so that for example you can install it if missing, you can have the following in your bash script:

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

回答 4

作为此答案的扩展:

对于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

As an extension of this answer:

For Python 2.*, pip show <package_name> will perform the same task.

For example pip show numpy will return the following or alike:

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

回答 5

您可以使用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包之间有区别。一个软件包可以包含多个模块,并且模块名称可能与软件包名称不匹配。

You can use the pkg_resources module from setuptools. For example:

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)

Note that there is a difference between python module and a python package. A package can contain multiple modules and module’s names might not match the package name.


回答 6

打开命令提示符类型

pip3 list

Open your command prompt type

pip3 list

回答 7

我想对此主题添加一些想法/发现。我正在编写一个脚本,检查定制程序的所有要求。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改用(易于使用),但是在这种情况下,模块将不会加载到内存中。

I’d like to add some thoughts/findings of mine to this topic. I’m writing a script that checks all requirements for a custom made program. There are many checks with python modules too.

There’s a little issue with the

try:
   import ..
except:
   ..

solution. In my case one of the python modules called python-nmap, but you import it with import nmap and as you see the names mismatch. Therefore the test with the above solution returns a False result, and it also imports the module on hit, but maybe no need to use a lot of memory for a simple test/check.

I also found that

import pip
installed_packages = pip.get_installed_distributions()

installed_packages will have only the packages has been installed with pip. On my system pip freeze returns over 40 python modules, while installed_packages has only 1, the one I installed manually (python-nmap).

Another solution below that I know it may not relevant to the question, but I think it’s a good practice to keep the test function separate from the one that performs the install it might be useful for some.

The solution that worked for me. It based on this answer How to check if a python module exists without importing it

from imp import find_module

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

NOTE: this solution can’t find the module by the name python-nmap too, I have to use nmap instead (easy to live with) but in this case the module won’t be loaded to the memory whatsoever.


回答 8

如果您希望脚本安装缺少的软件包并继续,则可以执行以下操作(在“ 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))

If you’d like your script to install missing packages and continue, you could do something like this (on example of ‘krbV’ module in ‘python-krbV’ package):

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

回答 9

一种快速的方法是使用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
$

A quick way is to use python command line tool. Simply type import <your module name> You see an error if module is missing.

$ 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
$

回答 10

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

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

Hmmm … the closest I saw to a convenient answer was using the command line to try the import. But I prefer to even avoid that.

How about ‘pip freeze | grep pkgname’? I tried it and it works well. It also shows you the version it has and whether it is installed under version control (install) or editable (develop).


回答 11

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

You can use this:

class myError(exception):
 pass # Or do some thing like this.
try:
 import mymodule
except ImportError as e:
 raise myError("error was occurred")

回答 12

在终端类型

pip show some_package_name

pip show matplotlib

In the Terminal type

pip show some_package_name

Example

pip show matplotlib

回答 13

我想评论@ 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

I would like to comment to @ice.nicer reply but I cannot, so … My observations is that packages with dashes are saved with underscores, not only with dots as pointed out by @dwich comment

For example, you do pip3 install sphinx-rtd-theme, but:

  • importlib.util.find_spec(sphinx_rtd_theme) returns an Object
  • importlib.util.find_spec(sphinx-rtd-theme) returns None
  • importlib.util.find_spec(sphinx.rtd.theme) raises ModuleNotFoundError

Moreover, some names are totally changed. For example, you do pip3 install pyyaml but it is saved simply as yaml

I am using python3.8


回答 14

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

回答 15

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

Go option #2. If ImportError is thrown, then the package is not installed (or not in sys.path).