我编写了一个Python模块,我有两个版本:纯Python实现和C扩展。我编写了__init__.py
文件,以便它尝试导入C扩展,如果失败,它会导入纯Python代码(这是合理的吗?)。
现在,我想知道分发此模块的最佳方式是什么(例如,写setup.py
),以便有或没有设施的人可以轻松地使用它来构建或使用C扩展,只需运行:
python setup.py install
我的经验有限,但我看到两种可能的情况:
答案 0 :(得分:7)
(这是合理的吗?)。
是的,非常明智。
要捕获“没有合适的C编译器案例”:对setup(...)
的调用将在出现问题时执行sys.exit。因此,首先在ext_modules
:
try
参数
try:
setup(..., ext_modules=...)
except SystemExit: ...
并在except
子句中,再次致电setup(...)
,不用 ext_modules
(因此它放弃了构建和安装扩展程序)。正在安装的用户仍会看到诸如“无法执行gcc-4.0:没有这样的文件或目录”之类的消息,但是您可以适当地添加自己的消息以通知用户这没什么大不了的,并且您正在尝试再次尝试扩展模块。
为了支持非CPython实现,在setup.py
中你可以测试sys.version
(我不确定每个非CPython实现的值是什么,但是IronPython有{{1}例如,在那里使用子串,以避免尝试'IronPython'
部分。如果你在支票中错过了一些这样的实现,那么try / except应该可能会捕获大多数其他的,只需要适量的浪费工作; - )。
答案 1 :(得分:0)
“尝试导入C扩展,如果失败,则导入纯Python代码(这是合理的吗?)。”
几乎。阅读cStringIO
和StringIO
。另请阅读cPickle
和Pickle
。另请阅读cElementTree
和ElementTree
。
如果无法构建C版本,那就是一个用例。纯Python版本是唯一可用的版本。
但是,如果可以构建C版本,我仍有很好的理由拒绝它。主要的,我会考虑拒绝C版本,因为它可能不允许我的应用程序所需的子类深度。
我不想被迫使用C版本,因为我碰巧有正确的编译器。我更喜欢自己做出这些决定。
因此,我不喜欢您的模块的某些部分为我做出架构决策的想法。我更喜欢选择要导入的内容。如果C版本不存在,那不会改变我的决策过程,因为我可能仍在创建纯Python版本的子类。
底线。自动化程度更低。提供两个模块。我更喜欢选择要导入哪一个。
答案 2 :(得分:0)
根据documentation for Planar,您可以制作setup.py
文件以正常构建C扩展名,然后:
从源代码分发或存储库使用构建和安装Planar:
python setup.py install
要仅安装纯Python模块而不编译,请使用:
python setup.py build_py install --skip-build