这展示了一个用Cython包装C ++ dll的简单例子。它将涵盖以下主要步骤:
使用Visual Studio使用C ++创建示例DLL。
用Cython包裹DLL,以便可以在Python中调用它。
假定您已安装Cython,并可以在Python中成功导入它。
对于DLL步骤,还假定您熟悉在Visual Studio中创建DLL。
完整的示例包括以下文件的创建:
complexFunLib.h:C ++ DLL源的头文件
complexFunLib.cpp:C ++ DLL源的CPP文件
ccomplexFunLib.pxd:Cython“头文件”
complexFunLib.pyx:Cython“包装器”文件
setup.py:complexFunLib.pyd使用Cython创建的Python安装文件
run.py:导入已编译的Cython包装的DLL的示例Python文件
如果您已经有了DLL和标头源文件,请跳过此步骤。首先,我们创建C ++源,使用Visual Studio从中编译DLL。在这种情况下,我们要使用复杂的指数函数进行快速数组计算。以下两个函数对数组and进行计算,结果存储在中。有两种功能可同时满足单精度和双精度。请注意,这些示例函数使用OpenMP,因此请确保在项目的Visual Studio选项中启用了OpenMP。k*exp(ee)keeres
H档
// Avoids C++ name mangling with extern "C" #define EXTERN_DLL_EXPORT extern "C" __declspec(dllexport) #include <complex> #include <stdlib.h> // 处理64位复数,即两个32位(4字节)浮点数 EXTERN_DLL_EXPORT void mp_mlt_exp_c4(std::complex<float>* k, std::complex<float>* ee, int sz, std::complex<float>* res, int threads); // 处理128位复数,即两个64位(8字节)浮点数 EXTERN_DLL_EXPORT void mp_mlt_exp_c8(std::complex<double>* k, std::complex<double>* ee, int sz, std::complex<double>* res, int threads);
CPP文件
#include "stdafx.h" #include <stdio.h> #include <omp.h> #include "complexFunLib.h" void mp_mlt_exp_c4(std::complex<float>* k, std::complex<float>* ee, int sz, std::complex<float>* res, int threads) { // 使用Open MP并行指令进行多处理 #pragma omp并行num_threads(线程) { #编译指示 for (int i = 0; i < sz; i++) res[i] = k[i] * exp(ee[i]); } } void mp_mlt_exp_c8(std::complex<double>* k, std::complex<double>* ee, int sz, std::complex<double>* res, int threads) { // 使用Open MP并行指令进行多处理 #pragma omp并行num_threads(线程) { #编译指示 for (int i = 0; i < sz; i++) res[i] = k[i] * exp(ee[i]); } }
接下来,我们创建包装C ++ DLL所需的Cython源文件。在此步骤中,我们进行以下假设:
您已经安装了Cython
您拥有一个有效的DLL,例如上述的DLL
最终目标是创建将这些Cython源文件与原始DLL结合使用,以编译.pyd可作为Python模块导入并公开用C ++编写的函数的文件。
PXD文件
该文件对应于C ++头文件。在大多数情况下,您可以通过Cython特定的较小更改将标头复制粘贴到此文件中。在这种情况下,使用了特定的Cython复合体类型。请注意c在开头添加ccomplexFunLib.pxd。这不是必需的,但是我们发现这样的命名约定有助于维护组织。
cdef extern from "complexFunLib.h": void mp_mlt_exp_c4(float complex* k, float complex* ee, int sz, float complex* res, int threads); void mp_mlt_exp_c8(double complex* k, double complex* ee, int sz, double complex* res, int threads);
PYX文件
该文件对应于C ++cpp源文件。在此示例中,我们将指向Numpyndarray对象的指针传递给导入DLL函数。也可以将内置的Cythonmemoryview对象用于数组,但是其性能可能不如ndarray对象(但是语法明显更清晰)。
cimport ccomplexFunLib # Import the pxd "header" # 对于Numpy导入,请注意,C导入大多数在Python导入之后 import numpy as np # 导入Python Numpy cimport numpy as np # 导入C块 # 从Python和C stdlib导入一些功能 fromcpython.pycapsulecimport * # Python包装函数。 # 请注意,可以在签名中添加类型 def mp_exp_c4(np.ndarray[np.complex64_t, ndim=1] k, np.ndarray[np.complex64_t, ndim=1] ee, int sz, np.ndarray[np.complex64_t, ndim=1] res, int threads): ''' TODO: Python docstring ''' # 在参数上调用导入的DLL函数。 # 注意,我们正在传递一个指向每个数组中第一个元素的指针 ccomplexFunLib.mp_mlt_exp_c4(&k[0], &ee[0], sz, &res[0], threads) def mp_exp_c8(np.ndarray[np.complex128_t, ndim=1] k, np.ndarray[np.complex128_t, ndim=1] ee, int sz, np.ndarray[np.complex128_t, ndim=1] res, int threads): ''' TODO: Python docstring ''' ccomplexFunLib.mp_mlt_exp_c8(&k[0], &ee[0], sz, &res[0], threads)
setup.py
该文件是执行Cython编译的Python文件。其目的是生成编译后的.pyd文件,然后可以由Python模块将其导入。在这个例子中,我们一直所需的所有文件(即complexFunLib.h,complexFunLib.dll,ccomplexFunLib.pxd和complexFunLib.pyx)在同一目录中setup.py。
创建此文件后,应使用以下参数从命令行运行该文件: build_ext --inplace
一旦执行了该文件,它应产生一个.pyd文件而不会引起任何错误。请注意,在某些情况下,如果有错误,.pyd可能会创建,但无效。setup.py使用生成的之前,请确保在执行时不会抛出任何错误.pyd。
fromdistutils.coreimport setup fromdistutils.extensionimport Extension fromCython.Distutilsimport build_ext import numpy as np ext_modules = [ Extension('complexFunLib', ['complexFunLib.pyx'], # 请注意,此处指定了C ++语言 # 默认语言是C language="c++", libraries=['complexFunLib'], library_dirs=['.']) ] setup( name = 'complexFunLib', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules, include_dirs=[np.get_include()] # 这将获取所有必需的Numpy核心文件 )
运行
现在complexFunLib可以直接导入到Python模块中,并调用包装的DLL函数。
import complexFunLib import numpy as np # 创建要求幂的非平凡复数数组, # 即res = k * exp(ee) k = np.ones(int(2.5e5), dtype='complex64')*1.1234 + np.complex64(1.1234j) ee = np.ones(int(2.5e5), dtype='complex64')*1.1234 + np.complex64(1.1234j) sz =k.size # 获取大小整数 res = np.zeros(int(2.5e5), dtype='complex64') # 创建结果数组 # 通话功能 complexFunLib.mp_exp_c4(k, ee, sz, res, 8) # 打印结果 print(res)
问题内容: 我有一个接受回调的C ++函数,如下所示: 我想通过给它一个闭包从Cython调用此函数,即,如果我从C ++调用它,我会用lambda来完成。如果这是一个C函数,它将有一些额外的参数: 然后我只想通过的(有更详细的在这里例子)。 有没有办法以C ++的方式做更多的事情,而不必诉诸显式的? 问题答案: 我相信您的目标是将可调用的Python对象传递给接受的对象。您需要创建一些C ++代
问题 你想使用Cython来创建一个Python扩展模块,用来包装某个已存在的C函数库。 解决方案 使用Cython构建一个扩展模块看上去很手写扩展有些类似, 因为你需要创建很多包装函数。不过,跟前面不同的是,你不需要在C语言中做这些——代码看上去更像是Python。 作为准备,假设本章介绍部分的示例代码已经被编译到某个叫 libsample 的C函数库中了。 首先创建一个名叫 csample.p
问题内容: 我想从Python应用程序调用C库。我不想包装整个API,只包装与我的情况相关的函数和数据类型。如我所见,我有三个选择: 在C中创建一个实际的扩展模块。可能有点过头了,我还想避免学习扩展编写的开销。 使用Cython将C库的相关部分公开给Python。 使用Python与外部库进行通信,从而完成整个工作。 我不确定2)还是3)是更好的选择。3)的优点是它是标准库的一部分,并且生成的代码
问题内容: 我有许多C函数,我想从python调用它们。cython似乎是要走的路,但我无法真正找到实现此目的的示例。我的C函数如下所示: 我要做的就是指定前三个参数(一个字符串和两个整数),并恢复8个numpy数组(或python列表。所有双精度数组都有N个元素)。我的代码假定指针指向已分配的内存块。同样,产生的C代码应该链接到一些外部库。 问题答案: 这是一个从逻辑上将numpy数组传递给外部
准确说Cython是单独的一门语言,专门用来写在Python里面import用的扩展库。实际上Cython的语法基本上跟Python一致,而Cython有专门的“编译器”先将 Cython代码转变成C(自动加入了一大堆的C-Python API),然后使用C编译器编译出最终的Python可调用的模块。
问题内容: 我刚刚开始熟悉Cython,尝试将一些结构从C库包装到Python方法和类。我真正不了解的是从(初始化的)C结构到相应的Python类的转换应该如何工作。我在这里想念的是什么: C头文件中的片段: 我的.pxd对应的代码段: 我的.pyx: 直到return语句的所有内容都可以正常工作。我在等中获得了正确的值。但是return语句中的强制转换似乎不正确或缺少更多信息。发出Python段