如何创建 Python 模块分发以优雅地回退到纯 Python 代码

发布于 2024-08-24 14:37:36 字数 466 浏览 5 评论 0原文

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

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

python setup.py install

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

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

I have written a Python module, and I have two versions: a pure Python implementation and a C extension. I've written the __init__.py file so that it tries to import the C extension, and if that fails, it imports the pure Python code (is that reasonable?).

Now, I'd like to know what is the best way to distribute this module (e.g. write setup.py) so it can be easily used by people with or without the facility to build, or use, the C extension, just by running:

python setup.py install

My experience is limited, but I see two possible cases:

  • User does not have MS Visual Studio, or the GCC compiler suite, installed on their machine, to build the C extension
  • User is running IronPython, Jython, or anything other than CPython. I only have used CPython. So I'm not sure how I could distribute this module so that it would work smoothly and be easy to install on those platforms, if they're unable to use the C extension.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无声静候 2024-08-31 14:37:36

(这合理吗?)。

是的,完全明智。

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

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 无论如何都可能会捕获大多数其他实现,只是浪费了一定量的工作;-)。

(is that reasonable?).

Yep, perfectly sensible.

To catch the "no suitable C compiler case": the call to setup(...) will do a sys.exit in case of problems. So, first try it with the ext_modules argument set as desired, within a try:

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

and in the except clause, call setup(...) again without the ext_modules (so it gives up on building and installing the extensions). The user who's installing will still see messages like "unable to execute gcc-4.0: No such file or directory", but you can appropriately add your own messages to inform the user that it's no big deal and that you're trying again without the extension modules.

To support non-CPython implementations, in your setup.py you can test sys.version (I'm not sure what the value will be for each non-CPython implementation, but IronPython has an 'IronPython' substring there, for example), to avoid even trying the ext_modules part. If you miss some such implementation in your checks, the try/except should probably catch most others anyway, just with a modest amount of wasted work;-).

月寒剑心 2024-08-31 14:37:36

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

几乎。了解 cStringIOStringIO。另请阅读有关 cPicklePickle 的信息。另请阅读有关 cElementTreeElementTree 的内容。

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

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

我不想仅仅因为我碰巧有正确的编译器而被迫使用C版本。我更喜欢自己做出这些决定。

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

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

"tries to import the C extension, and if that fails, it imports the pure Python code (is that reasonable?)."

Almost. Read about cStringIO and StringIO. Also read about cPickle and Pickle. Also read about cElementTree and ElementTree.

If the C version can't be built, that's one use case. The pure Python version is the only one available.

If the C version can be built, however, I still have good reasons for declining it. Primary, I would consider declining the C version because it may not allow the depth of subclass that I require for my application.

I don't want to be forced to use the C version, just because I happened to have the correct compiler. I prefer to make those decisions on my own.

Consequently, I don't like the idea of some part of your module making my architecture decisions for me. I prefer to choose which to import. If the C version doesn't exist, that doesn't change my decision process, because I may still be creating subclasses of the pure Python version.

Bottom line. Automate less. Provide the two modules. I prefer to choose which one to import.

无声情话 2024-08-31 14:37:36

根据 Planar 文档,您可以进行设置.py 文件用于正常构建 C 扩展,然后:

要从源代码发行版或存储库构建并安装 Planar,请使用:

python setup.py install

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

python setup.py build_py install --skip-build

According to the documentation for Planar, you can make the setup.py file for building the C extensions as normal, and then:

To build and install Planar from the source distribution or repository use:

python setup.py install

To install only the pure-Python modules without compiling, use:

python setup.py build_py install --skip-build
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文