Python:以编程方式运行;pip列表“;

Python:以编程方式运行;pip列表“;,python,pip,Python,Pip,我正在编写一些代码来报告和协调两个pip管理的python安装之间的差异 如何以编程方式获取由pip列表提供的信息,而不进行pip子程序调用?Python 3.6和pip 19.0.1的更新 > from pip._internal.utils.misc import get_installed_distributions > p = get_installed_distributions() > pprint.pprint(p) [wheel 0.32.3 (/usr/lo

我正在编写一些代码来报告和协调两个pip管理的python安装之间的差异


如何以编程方式获取由
pip列表提供的信息,而不进行pip子程序调用?

Python 3.6和pip 19.0.1的更新

> from pip._internal.utils.misc import get_installed_distributions
> p = get_installed_distributions()
> pprint.pprint(p)

[wheel 0.32.3 (/usr/local/lib/python3.7/site-packages),
 wcwidth 0.1.7 (/usr/local/lib/python3.7/site-packages),
 virtualenv 16.0.0 (/usr/local/lib/python3.7/site-packages),
 virtualenv-clone 0.3.0 (/usr/local/lib/python3.7/site-packages),
 urllib3 1.24.1 (/usr/local/lib/python3.7/site-packages),
 typing 3.6.6 (/usr/local/lib/python3.7/site-packages),
 terminaltables 3.1.0 (/usr/local/lib/python3.7/site-packages),
 ...

原始答案

Pip只是python模块,所以只需导入它并调用
list

import pip

pip.main(['list'])

# you can get details on package using show:

pip.main(['show', 'wheel'])
好的,有更好的方法:

pip.utils.get_installed_distributions()
返回已安装程序包的列表

packages = pip.utils.get_installed_distributions()

p = packages[0]

p.project_name 
p.version
p.egg_name
p.location
您可以从源代码中看到
pip list
正在做什么

另外,
get\u installed\u发行版
接受全部参数以仅返回本地包(来自当前virtualenv)等。请参阅帮助

还有来自供应商模块的底层低级命令:

[p for p in pip._vendor.pkg_resources.working_set]

然而,
get\u installed\u发行版提供了更简单的api

为了完整起见,下面是vittore的
pip.main()
思想,它通过捕获stdout而得到了充实。当然,使用
get\u installed\u distributions()
是首选解决方案

import contextlib
@contextlib.contextmanager
def capture():
    import sys
    from cStringIO import StringIO
    oldout,olderr = sys.stdout, sys.stderr
    try:
        out=[StringIO(), StringIO()]
        sys.stdout,sys.stderr = out
        yield out
    finally:
        sys.stdout,sys.stderr = oldout, olderr
        out[0] = out[0].getvalue()
        out[1] = out[1].getvalue()

with capture() as out:
    import pip
    pip.main(['list'])

print out
    ['awscli (1.7.45)\nboto (2.38.0) ...

截至2019年2月1日的顶级答案已经过时,不再适用于较新版本的pip

但不用担心-仍然可以通过编程方式获取包列表:

选项: A.\u内部主管道

from pip import _internal
_internal.main(['list'])
这将打印出带有包的三列。版本和位置

请注意,不建议使用pip的内部api

A.北大资源

import pkg_resources
print([p.project_name for p in pkg_resources.working_set])
# note that this is same as calling pip._vendor.pkg_resources.working_set
B.国际热核聚变实验堆模块

import pkg_resources
print([p.project_name for p in pkg_resources.working_set])
# note that this is same as calling pip._vendor.pkg_resources.working_set
执行需要很长时间(在配备I5 CPU、SSD和8 gigs ram的计算机上约300毫秒)。 好处是它将有一个更广泛的模块列表,并将输出可导入的名称

例如:作为dateutil导入,但iter_模块将为您提供可导入的名称:dateutil

from pkgutil import iter_modules
print([p.name for p in iter_modules()])
C.通过子流程在命令行中调用pip

import pkg_resources
print([p.project_name for p in pkg_resources.working_set])
# note that this is same as calling pip._vendor.pkg_resources.working_set
解决这个问题的方法很简单,我将把它作为练习留给读者


我懒得这么做,祝你好运D

使用操作系统模块或系统模块

import os 
import subprocess as su
os.system("pip list")
su.call(["pip","list"])

如果一个lib在内部使用子进程这样做,这会是一个问题吗?只要我的代码不必知道在我不熟悉的各种系统上调用子进程的复杂性,就可以了。我在看到@vittore的答案之前写下了这个问题。我喜欢这个答案。有没有理由使用一个虚拟环境,你可以直接销毁并重新创建它,而不是一个选项?这是做这件事的标准方法。@jpmc,不确定,它们不是我的安装。。。但我会把你的纸条传过去!如何获得结果输出?x=pip.main(['list'])将x设置为0,表示成功执行,结果将转到标准输出。这里给出了许多方法:但是我不喜欢其中任何一种,因为它们都很麻烦,让我看看如何将其称为稍微不同的方法,@vittore我找不到pip模块的文档。我一直在寻找。但是这个模块没有任何内容api@Cripto只要浏览一下pip源代码,就像我做的那样=)谢谢你,事实上看起来是这样的(他们甚至在最后使用它),但这是一个让我困惑的变化。同时,我从
setuptools
to使用了
pkg_资源
。pip不再支持main-请看,我已经验证了A和B,并且接受了这个答案。太棒了!如果您还想知道包的版本,我想使用
pkg_resources
的方法是最好的,因为返回的对象有一个
.version
成员包含它。这是最有用的答案。但是这两个调用的输出都是int,为什么?