1. FlyPython首页
  2. Python高级话题

Pip vs Conda:深入比较 Python 的两种打包系统

如果您在数据科学或科学计算领域使用 Python,您很快就会发现 Python 有两种不同的打包系统:pip 和 Conda。这就提出了一些问题:

  • 它们它们
  • 两者之间有什么取舍?
  • 哪个?

虽然不可能在每种情况下都回答这个问题,但在本文中,您将了解基本差异,仅限于:

  • 仅限 Python;Conda 支持其他语言,但我不会深入讨论。
  • Linux,包括在 Docker 上运行,但也提到了 macOS 和 Windows。
  • 专注于 Conda-Forge 包存储库;Conda 有多个包存储库或“通道”。

最后,您应该了解 Conda 存在的原因、何时可能需要使用它,以及在选择每一个之间的权衡。

出发点:哪种依赖?

pip 和 Conda 打包的根本区别在于它们放在包中的内容。

  • Pip 包是 Python 库,如 NumPy 或matplotlib.
  • Conda 包包括 Python 库(NumPy 或matplotlib)、C 库 ( libjpeg) 和可执行文件(如 C 编译器,甚至 Python 解释器本身)。

Pip:仅限 Python 库

例如,假设您要安装带有 NumPy、Pandas 和 gnuplot 渲染工具(与 Python 无关的工具)的 Python 3.9。这是 pip 的requirements.txt样子:

安装 Python 和 gnuplot超出了 pip的范围您作为用户必须自己处理。例如,您可以使用 Docker 映像执行此操作:

FROM ubuntu:20.04
RUN apt-get update && apt-get install -y gnuplot python3.9
COPY requirements.txt .
RUN pip install -r requirements.txt

Python 解释器和 gnuplot 都需要来自系统包,在这种情况下是 Ubuntu 的包。

Conda:任何依赖都可以是一个 Conda 包(几乎)

对于 Conda,Python 和 gnuplot 只是更多的 Conda 包,与 NumPy 或 Pandas 没有什么不同。environment.yml对应(有点)的requirements.txt,我们看到上面会包括所有这些软件包:

name: myenv
channels:
  - conda-forge
dependencies:
  - python=3.9
  - numpy
  - pandas
  - gnuplot

Conda 仅依赖于操作系统的基本功能,如标准 C 库。上面的一切都是 Conda 包,而不是系统包。

如果对应Dockerfile我们可以看到差异; 无需安装任何系统包:

FROM continuumio/miniconda3
COPY environment.yml .
RUN conda env create

此基础映像附带预安装的 Conda,但我们不依赖任何现有的 Python 安装,我们将在新环境中安装一个新的。

注意:在讨论的非常具体的主题之外,本文中的 Dockerfile 不是最佳实践的示例,因为增加的复杂性会掩盖本文的要点。

Python on Docker 生产手册为确保您遵循获得安全、正确、快速 Dockerfile 所需的所有最佳实践,请查看Python on Docker Production Handbook

为什么 Conda 打包一切

为什么 Conda 决定打包所有东西,包括 Python 解释器?这对你有什么好处?部分是关于便携性和可再现性。

  1. 跨操作系统的可移植性:无需在 Linux、macOS 和 Windows 上以三种不同的方式安装 Python,您可以在这三种方式上使用相同的方式environment.yml
  2. 重现性:可以固定几乎整个堆栈,从 Python 解释器向上。
  3. 配置一致:不需要以两种不同的方式安装系统包和Python包;(几乎)一切都可以放在一个文件中,environment.yml.

但它也解决了另一个问题:如何处理需要编译代码的 Python 库。这是一个足够大的主题,它接下来会有一个全新的部分。

超越纯 Python:打包编译的扩展

在 Python 打包的早期,一个包只包含需要安装的源代码。对于纯 Python 包,这工作得很好,现在仍然如此。但是当您需要编译一些 Rust 或 C 或 C++ 或 Fortran 代码作为构建包的一部分时会发生什么?

解决方案#1:自己编译

最初的解决方案是让每个用户在安装时自己编译代码。这可能很慢,浪费资源,配置起来通常很痛苦,而且仍然没有解决很大一部分问题:共享库依赖项。

例如,枕头图像图形库依赖于第三方共享库,如libpnglibjpeg为了自己编译 Pillow,您必须安装所有这些,以及它们的开发头文件。在 Linux 或 macOS 上,您可以安装系统包或 Homebrew 包;对于 Windows,这可能更困难。但是您将不得不为每个操作系统甚至 Linux 发行版编写不同的配置。

解决方案#2:Pip轮

pip 解决这个问题的方法是使用称为“轮子”的包,它可以包含已编译的代码。为了处理像 的共享库依赖项libpng,任何共享库外部依赖项都被捆绑在轮子内部。

例如,让我们看看 Linux 的 Pillow wheel;轮子只是一个 ZIP 文件,所以我们可以使用标准的 ZIP 工具:

$ zipinfo Pillow.whl
...
Pillow.libs/libpng16-213e245f.so.16.37.0
Pillow.libs/libjpeg-183418da.so.9.4.0
...
PIL/FpxImagePlugin.py
PIL/PalmImagePlugin.py
...
PIL/_imagingcms.cpython-39-x86_64-linux-gnu.so
...

轮子包括 Python 代码、编译的 Python 扩展和第三方共享库,如libpnglibjpeg. 这有时会使包变大,因为可能会安装第三方共享库的多个副本,每个轮一个。

解决方案 #3:Conda 包

Conda 包对第三方共享库采用不同的方法。
libjpeglibpng打包为额外的 Conda 包:

$ conda install -c conda-forge pillow
...
The following NEW packages will be INSTALLED:

...
  jpeg               conda-forge/linux-64::jpeg-9d-h36c2ea0_0
...
  libpng             conda-forge/linux-64::libpng-1.6.37-h21135ba_2
...
  pillow             conda-forge/linux-64::pillow-7.2.0-py38h9776b28_2
  zstd               conda-forge/linux-64::zstd-1.5.0-ha95c52a_0
...

那些已安装libjpeglibpng然后可以被其他已安装的软件包所依赖。它们不是特定于轮子的,它们可用于 Conda 环境中的任何包。

Conda 可以做到这一点,因为它不仅仅是 Python 代码的打包系统;它可以轻松地打包共享库或可执行文件。

总结:pip 与 Conda

  点子 康达
安装 Python 是的,作为包裹
第三方共享库 车轮内 是的,作为包裹
可执行文件和工具 是的,作为包裹
Python源代码 是的,作为包裹 是的,作为包裹

PyPI 与 Conda-Forge

pip 和 Conda 之间的另一个根本区别不在于工具本身,而在于它们依赖的包存储库以及它们的工作方式。特别是,大多数 Python 程序将依赖于开源库,这些库需要从某个地方下载。对于这些,pip 依赖于PyPI,而 Conda 支持托管在Anaconda上的多个不同“通道”

默认的 Conda 频道由创建 Conda 的公司 Anaconda Inc 维护。它的软件包选择往往有限,更新程度较低,在稳定性和 GPU 支持方面具有一些潜在优势。除此之外,我对此知之甚少。

但是还有Conda-Forge社区频道,它打包了更多的软件包,而且往往是最新的,并且大多数时候您可能希望在那里获得 Conda 软件包。如果您需要默认频道的 GPU 包,您可以混合来自默认频道和 Conda-Forge 的包。

让我们将 PyPI 与 Conda-Forge 进行比较。

PyPI

PyPI 上的包通常由 Python 包的作者上传。例如,我是Fil memory profiler的作者,我还创建了PyPI 包

每个包维护者都可能以自己独特的方式编译或构建他们的包,维护自己的构建基础设施,选择自己的编译选项,等等。

例如,NumPy 可以依赖多个不同的 BLAS 库进行快速线性代数运算。维护者选择使用 OpenBLAS 构建他们的 PyPI 包;如果你想要另一个选择,比如英特尔的(也许?)更快的 MKL,除非你愿意自己编译代码,否则你就不走运了。

康达福吉

Conda-Forge 是一个社区项目,其中包维护者可以不同于包的原始作者。例如,即使我不是该的维护者,我也已提交对typeguardConda-Forge 配方的访问权限typeguard

Conda-Forge 拥有集中的构建系统,可以重新编译库、更新配方存储库,并且通常大规模自动化所有内容,而不是由每个包维护者以不同的方式完成自定义构建。例如,当新版本的 Python 3 出来时,会发生集中更新,所有单独的包维护者都会获得 PR,添加新的包;在 PyPI 上,这取决于个人维护者来解决。

由于打包基础设施是集中式的,Conda-Forge 能够让您选择要使用的 BLAS,它将用于 NumPy 和 SciPy 以及您使用的依赖于 BLAS 的任何其他包。

在 Conda 中处理 PyPI-only 包

虽然 Conda-Forge 有很多包,但并不是所有的包;许多 Python 包只能在 PyPI 上找到。您可以通过多种方式处理缺少这些软件包的问题。

在 Conda 环境中安装 pip 包

Conda 环境是 virtualenvs 的包装器;因此,您可以给pip install自己打电话如果你使用 anenvironment.yml来安装你的 Conda 包,你还可以添加 pip 包:

name: myenv
channels:
  - conda-forge
dependencies:
  - python=3.9
  - numpy
  - pandas
  - gnuplot
  - pip:
      # Package that is only on PyPI
      - sandu 

自己为 Conda-Forge 打包

因为 Conda-Forge 不需要代码的维护者进行打包,所以任何人都可以自愿向 Conda-Forge 添加一个包。那包括你!

对于许多 Python 包来说,这是一个非常简单的过程,而且非常自动化,因此处理新版本通常就像批准自动创建的 PR 一样简单。

总结:PyPI 与 Conda-Forge

  PyPI 康达福吉
谁创建包? 代码作者 任何人
建设基础设施 由作者维护 集中
开源 Python 库 基本上所有 许多
其他开源工具 没有任何 许多
Windows/Linux/macOS 包 通常,但由维护者决定 几乎总是

以下是您可能希望与任一工具一起使用的一些附加工具的快速摘要:

  康达
可复制的构建 pip-tools、pipenv、诗歌
虚拟环境 python -m venv, virtualenv 内置
安全扫描 大多数安全扫描仪 杰克
备择方案 诗歌pipenv 曼巴; 速度更快,强烈推荐

重申:如果您确实使用 Conda,我强烈建议您使用 Mamba 作为替代品。它支持相同的命令行选项并且速度更快。

你应该使用哪个?

那么你应该使用哪个,pip 还是 Conda?对于一般的 Python 计算,pip 和 PyPI 通常都可以,周围的工具往往会更好。

然而,对于数据科学或科学计算,Conda 打包第三方库的能力,以及 Conda-Forge 提供的集中式基础设施,意味着复杂包的设置通常会更容易。最后,哪种最适合您将取决于您的情况和要求;很可能两者都会好的。

原创文章,作者:flypython,如若转载,请注明出处:http://flypython.com/advanced-python/542.html