setuptools与distutils:为什么distutils仍然存在?
Python在打包和描述项目的工具上有一段复杂的历史,涉及到很多工具,比如标准库里的distutils
、distribute
、distutils2
和setuptools
(可能还有其他的)。看起来distribute
和distutils2
已经不再使用,取而代之的是setuptools
,这就留下了两个竞争的标准。
根据我的理解,setuptools
提供了比distutils
更多的选项(比如声明依赖、测试等),但是它还不在Python的标准库里(还没?)。
Python打包用户指南[1]现在推荐:
使用
setuptools
来定义项目并创建源分发。
并且解释说:
虽然你可以用纯
distutils
来处理很多项目,但它不支持定义对其他项目的依赖,并且缺少一些setuptools
提供的便利工具,这些工具可以自动正确填充包的元数据。由于setuptools
不在标准库中,它在不同版本的Python中也提供了更一致的功能集,并且(与distutils
不同),setuptools
会更新以支持即将到来的“Metadata 2.0”标准格式。即使是选择使用
distutils
的项目,当pip直接从源代码安装这些项目时(而不是从预构建的wheel文件安装),它实际上会使用setuptools
来构建你的项目。
然而,查看各种项目的setup.py文件会发现,这似乎并不是一个真正的标准。许多包仍然使用distutils
,而那些支持setuptools
的包往往会将setuptools
和distutils
混合使用,比如通过回退导入的方式:
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
接着尝试找到一种方法来编写一个可以被setuptools
和distutils
都安装的setup。这通常包括各种容易出错的依赖检查方式,因为distutils
在setup函数中不支持依赖。
为什么人们还在额外努力支持distutils
呢?难道setuptools
不在标准库里就是唯一的原因吗?distutils
有什么优势,而只支持setuptools
的setup.py文件又有什么缺点呢?
4 个回答
基本上,这是因为责任的划分。
setuptools
不是 Python 标准库的一部分,因为它是由第三方维护的,而不是 Python 核心团队。这意味着,除了其他方面:
- 它不在核心测试套件中,也不依赖于核心功能。
- 它本身并不设定附加模块的核心标准(比如它们的位置、导入方式、C 扩展的二进制接口等)。
- 它的更新和发布是独立于 Python 的版本发布的。
实际上,核心团队缩小了 distutils 的范围,将“核心标准”和“最小必要编译”的部分留给自己 而把所有其他的内容(扩展编译器/包格式/其他支持) 留给第三方。之前覆盖这些“扩展部分”的代码被保留下来以保持向后兼容。
来自 分发 Python 模块 — Python 2.7.12 文档:
虽然直接使用
distutils
正在逐步淘汰,但它仍然为当前的打包和分发基础设施奠定了基础,它不仅仍然是标准库的一部分,而且它的名字以其他方式继续存在(例如,用于协调 Python 打包标准开发的邮件列表的名称)。
其他操作系统的包也可能会单独提供 setuptools
和 pip
- 这是因为上述原因
- 而且当系统上已经有其他包管理器时,它们并不是必要的,甚至可能对可维护性有害。
虽然setuptools无疑是更好的工具,但我们仍然会提到和使用distutils,原因有几个。
首先,distutils几乎在所有地方都能找到。如果你想创建一个可以分享给别人的模块,而且没有什么复杂的要求,那么在你的工作机器上肯定能找到它。这一点在你需要支持旧版本的Python,或者在一个不熟悉的环境中工作时尤其重要。
其次,setuptools是在distutils的基础上进行改进的。它的结构和功能都是基于distutils的。setuptools的文档假设读者已经熟悉distutils,只讲述它是如何增强这个基础工具的。你可以把distutils想象成一种方言,而setuptools则是在这种方言上进行的提升。
我个人在新项目中的做法是,先假设我会使用distutils。只有当项目发展到需要setuptools的某个功能时,我才会进行升级。setuptools可以直接替代distutils,只需要在我的setup.py文件中做一行简单的修改。
setuptools不在标准库中是唯一的原因吗?
这只是一个原因。下面的内容直接来自于NumPy的setup.py
:
if len(sys.argv) >= 2 and ('--help' in sys.argv[1:] or
sys.argv[1] in ('--help-commands', 'egg_info', '--version',
'clean')):
# Use setuptools for these commands (they don't work well or at all
# with distutils). For normal builds use distutils.
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
所以NumPy如果能找到setuptools
就会优先使用它。但是SciPy以前也是这样做的,直到它被修改为在某些情况下优先使用distutils
。在提交日志中提到:
setuptools会给测试脚本设置可执行权限,这样Nose就拒绝运行它们。最好不要这样做。
当然,setuptools和distribute
的合并应该会在未来解决这些问题,但许多包仍然需要支持Python 2.6的安装。
看看这个StackOverflow的问题。它很好地解释了所有的打包方法,可能对你解决问题有帮助:distribute、distutils、setuptools和distutils2之间的区别?
Distutils 仍然是Python中打包的标准工具。它包含在标准库中(Python 2和Python 3.0到3.3)。它适用于简单的Python分发,但功能比较有限。它引入了一个叫做distutils的Python包,可以在你的setup.py脚本中导入。
Setuptools 是为了克服Distutils的局限性而开发的,它不包含在标准库中。它引入了一个命令行工具,叫做easy_install。它还引入了setuptools这个Python包,可以在你的setup.py脚本中导入,以及pkg_resources这个Python包,可以在你的代码中导入,用来查找与分发一起安装的数据文件。它的一个小问题是,它会对distutils这个Python包进行修改。它应该能很好地与pip配合使用。最新版本是在2013年7月发布的。
所以,正如你所看到的,setuptools应该优先于distutils。我理解你为什么会有这个问题,不过我认为distutils短期内不会失去支持,因为简单来说,它在很多流行的旧程序中仍然被使用。而且你可能知道,改变这些旧程序中的东西可能会非常麻烦,还会带来很多问题,比如不兼容,这会导致开发者不得不重写源代码。所以有这一点,还有distutils是标准Python库的一部分,而setuptools不是。所以,如果你现在在创建一个Python程序,建议使用setuptools,但要记住,没有distutils,setuptools也不会存在。