7

我写了一个 Python 模块,我有两个版本:一个纯 Python 实现和一个 C 扩展。我已经编写了__init__.py文件,以便它尝试导入 C 扩展名,如果失败,它会导入纯 Python 代码(这合理吗?)。

现在,我想知道分发这个模块(例如 write setup.py)的最佳方式是什么,这样无论有没有能力构建或使用 C 扩展的人都可以轻松地使用它,只需运行:

python setup.py install

我的经验有限,但我看到了两种可能的情况:

  • 用户没有在他们的机器上安装 MS Visual Studio 或 GCC 编译器套件来构建 C 扩展
  • 用户正在运行 IronPython、Jython 或 CPython 以外的任何东西。我只使用过 CPython。所以我不确定如何分发这个模块,以便它能够顺利运行并易于安装在这些平台上,如果他们无法使用 C 扩展。
4

3 回答 3

7

(这合理吗?)。

是的,完全明智。

捕捉“没有合适的 C 编译器情况”:调用setup(...)将执行 sys.exit 以防出现问题。ext_modules因此,首先在 a 中使用根据需要设置的参数进行尝试try

try:
  setup(..., ext_modules=...)
except SystemExit: ...

并且在该except子句中,setup(...)再次调用而不使用ext_modules(因此它放弃了构建和安装扩展)。正在安装的用户仍然会看到诸如“无法执行 gcc-4.0:没有这样的文件或目录”之类的消息,但是您可以适当地添加自己的消息以通知用户这没什么大不了的,并且您在没有扩展模块。

为了支持非 CPython 实现,setup.py您可以测试sys.version(我不确定每个非 CPython 实现的值是多少,但 IronPython 有一个'IronPython'子字符串,例如),以避免尝试该ext_modules部分。如果您在检查中错过了一些这样的实现,那么 try/except 可能无论如何都应该捕获大多数其他实现,只是浪费了少量的工作;-)。

于 2010-03-08T01:19:33.747 回答
0

根据Planar 的文档,您可以setup.py正常生成用于构建 C 扩展的文件,然后:

要从源分发或存储库构建和安装 Planar,请使用:

python setup.py install

要仅安装纯 Python 模块而不进行编译,请使用:

python setup.py build_py install --skip-build
于 2010-04-27T14:07:00.083 回答
0

“尝试导入 C 扩展,如果失败,它会导入纯 Python 代码(这合理吗?)。”

几乎。阅读cStringIOStringIO。另请阅读cPicklePickle。另请阅读cElementTreeElementTree

如果无法构建 C 版本,那是一个用例。纯 Python 版本是唯一可用的版本。

但是,如果可以构建 C 版本,我仍然有充分的理由拒绝它。主要的,我会考虑拒绝 C 版本,因为它可能不允许我的应用程序所需的子类深度。

我不想被迫使用 C 版本,只是因为我碰巧有正确的编译器。我更愿意自己做出这些决定。

因此,我不喜欢您的模块的某些部分为我做出架构决策的想法。我更喜欢选择要导入的内容。如果 C 版本不存在,那不会改变我的决策过程,因为我可能仍在创建纯 Python 版本的子类。

底线。减少自动化。提供两个模块。我更喜欢选择导入哪一个。

于 2010-03-08T03:41:31.570 回答