我已经考虑编写一个峰值拟合库有一段时间了。我对 Python 相当了解,并计划一开始就用 Python 实现所有内容,但预计我最终可能不得不用编译语言重新实现一些核心例程。

IIRC,Python 最初的职责之一是作为一种原型语言,但是 Python 在允许将函数、函子、对象传递给函数和方法方面相当自由,而我怀疑 C 或 Fortran 的情况并非如此。

关于设计我设想必须与编译语言接口的函数/类,我应该了解什么?这些潜在问题中有多少是由 cTypes、bgen、 斯威格, Boost.Python, 赛通 或者 Python SIP?

对于这个特定的用例,(一个拟合库)我想象允许用户将数学函数(高斯函数、洛伦兹函数等)定义为Python函数,然后可以将其传递给编译后的代码拟合库进行解释。传递和返回数组也很重要。

有帮助吗?

解决方案

最后一个我可以真正给出有价值答案的问题:)。

我为我的工作(光学测量技术博士学位)研究了 f2py、boost.python、swig、cython 和 Pyrex。我广泛使用了 swig、boost.python 以及 Pyrex 和 cython。我也用过ctypes。这是我的细分:

免责声明: :这是我的个人经历。我没有参与任何这些项目。

痛饮:与 c++ 配合得不好。应该是这样,但在 Linux 和 Mac OS X 上,链接步骤中的名称修改问题对我来说是一个非常头疼的问题。如果您有 C 代码并希望它与 python 接口,那么这是一个很好的解决方案。我根据自己的需要封装了 GTS,并且基本上需要编写一个可以连接的 C 共享库。我不会推荐它。

C类型:我使用 ctypes 编写了一个 libdc1394(IEEE 相机库)包装器,这是一次非常直接的体验。您可以在以下位置找到代码 https://launchpad.net/pydc1394. 。将标头转换为 python 代码需要做很多工作,但之后一切都会可靠地工作。如果您想连接外部库,这是一个好方法。Ctypes也在python的stdlib中,所以每个人都可以立即使用你的代码。这也是快速使用 python 中的新库的好方法。我可以推荐它与外部库连接。

Boost.Python: :很好玩儿。如果您已经拥有自己的 C++ 代码并想在 python 中使用,请这样做。通过这种方式将 C++ 类结构转换为 Python 类结构非常容易。如果您有需要在 python 中使用的 C++ 代码,我推荐它。

耐热玻璃/Cython: 使用 Cython,而不是 Pyrex。时期。Cython 更先进,使用起来更愉快。现在,我用 cython 做所有我以前用 SWIG 或 Ctypes 做的事情。如果你的 python 代码运行速度太慢,这也是最好的方法。这个过程绝对精彩:您将 python 模块转换为 cython 模块,构建它们并继续进行分析和优化,就像它仍然是 python 一样(无需更改工具)。然后,您可以应用尽可能多(或尽可能少)的 C 代码与 Python 代码混合。这比用 C 重写应用程序的整个部分要快得多;您只需重写内部循环即可。

时间安排: :ctypes 的调用开销最高(~700ns),其次是 boost.python(322ns),然后直接是 swig(290ns)。Cython 具有最低的调用开销(124ns)和最好的反馈(cProfile 支持!)。这些数字来自我的盒子,调用一个简单的函数,该函数从交互式 shell 返回一个整数;因此,模块导入开销不是定时的,只有函数调用开销是定时的。因此,通过分析和使用 cython 快速获取 Python 代码是最简单、最高效的方法。

概括: :对于您的问题,请使用 Cython ;)。我希望这个纲要对某些人有用。我很乐意回答任何剩余的问题。


编辑: :我忘了提及:出于数字目的(即连接到 NumPy),请使用 Cython;他们对此表示支持(因为他们基本上为此目的开发了 cython)。所以这应该是你决定的另一个+1。

其他提示

我没有使用过 SWIG 或 SIP,但我发现可以使用以下命令编写 Python 包装器 升压Python 非常强大并且相对容易使用。

我不清楚您在 C/C++ 和 python 之间传递类型的要求是什么,但是您可以通过将 C++ 类型暴露给 python 或使用泛型来轻松做到这一点 升压::python::对象 C++ API 的参数。您还可以注册转换器以自动将 python 类型转换为 C++ 类型,反之亦然。

如果您计划使用 boost.python, 教程 是一个很好的起点。

我已经实现了一些与您需要的类似的东西。我有一个C ++函数,该函数接受Python函数和图像作为参数,并将Python函数应用于图像中的每个像素。

Image* unary(boost::python::object op, Image& im)
{
    Image* out = new Image(im.width(), im.height(), im.channels());
    for(unsigned int i=0; i<im.size(); i++)
    {
        (*out)[i] == extract<float>(op(im[i]));
    }
    return out;
}

在本例中,Image 是一个暴露给 python 的 C++ 对象(具有浮点像素的图像),op 是一个 python 定义的函数(或者实际上是任何具有 __call__ 属性的 python 对象)。然后,您可以按如下方式使用此函数(假设一元位于被调用的图像中,该图像还包含 Image 和加载函数):

import image
im = image.load('somefile.tiff')
double_im = image.unary(lambda x: 2.0*x, im)

至于使用带有 boost 的数组,我个人还没有这样做,但我知道使用 boost 将数组暴露给 python 的功能是可用的 - 可能会有帮助。

规划最终过渡到编译代码的最佳方法是将性能敏感部分编写为简单函数的模块 功能风格 (无状态且无副作用),它接受并返回基本数据类型。

这将提供从 Python 原型代码到最终编译代码的一对一映射,并允许您使用 c类型 轻松并避免一大堆令人头痛的事情。

对于峰值拟合,您几乎肯定需要使用数组,这会使事情变得有点复杂,但使用 ctypes 仍然非常可行。

如果你确实想使用更复杂的数据结构,或者修改传递的参数, 斯威格 或者 Python 的标准 C 扩展接口 会让你做你想做的事,但会带来一些麻烦。

对于您正在做的事情,您可能还想查看 数值模拟, ,它可能会完成一些您想要推送给 C 的工作,并提供 在 Python 和 C 之间来回移动数据的一些额外帮助.

f2py (部分 numpy) 是 SWIG 和 boost.python 的更简单替代方案,用于包装 C/Fortran 数字运算代码。

根据我的经验,有两种简单的方法可以从 Python 代码调用 C 代码。还有其他方法,所有这些方法都更烦人和/或更冗长。

第一个也是最简单的方法是将一堆 C 代码编译为单独的共享库,然后使用 ctypes 调用该库中的函数。不幸的是,传递除基本数据类型之外的任何内容都非常重要。

第二种最简单的方法是用 C 语言编写 Python 模块,然后调用该模块中的函数。您可以将任何您想要的内容传递给这些 C 函数,而无需跳过任何麻烦。从这些 C 函数调用 Python 函数或方法很容易,如下所述: https://docs.python.org/extending/extending.html#calling-python-functions-from-c

我没有足够的 SWIG 经验来提供明智的评论。虽然可以通过 ctypes 将自定义 Python 对象传递给 C 函数,或者在 C 中定义新的 Python 类,但这些事情既烦人又冗长,我建议采用上述两种方法之一。

Python 在允许将函数、函子、对象传递给函数和方法方面相当自由,而我怀疑 C 或 Fortran 的情况并非如此。

在 C 中,您不能将函数作为参数传递给函数,但可以传递函数指针,这与函数一样好。

我不知道当您尝试集成 C 和 Python 代码时这会有多大帮助,但我只是想澄清一个误解。

除了上面的工具之外,我还推荐使用 耐热玻璃 (用于创建 Python 扩展模块)或 心理科 (作为 Python 的 JIT 编译器)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top