当前位置: 首页 > 面试题库 >

用cython简单包装C代码

袁文景
2023-03-14
问题内容

我有许多C函数,我想从python调用它们。cython似乎是要走的路,但我无法真正找到实现此目的的示例。我的C函数如下所示:

void calculate_daily ( char *db_name, int grid_id, int year,
                       double *dtmp, double *dtmn, double *dtmx, 
                       double *dprec, double *ddtr, double *dayl, 
                       double *dpet, double *dpar ) ;

我要做的就是指定前三个参数(一个字符串和两个整数),并恢复8个numpy数组(或python列表。所有双精度数组都有N个元素)。我的代码假定指针指向已分配的内存块。同样,产生的C代码应该链接到一些外部库。


问题答案:

这是一个从逻辑上将numpy数组传递给外部C函数的小巧但完整的示例

fc( int N, double* a, double* b, double* z )  # z = a + b

使用Cython。(这肯定是众所周知的人。欢迎评论。最后更改:2011年2月23日,对于Cython 0.14。)

首先阅读或略读 Cython构建
并与NumPy一起使用Cython。

2个步骤:

  • python f-setup.py build_ext --inplace
    接通f.pyxfc.cpp- >f.so中,动态库

  • python test-f.py
    import f负载f.so; f.fpy( ... )调用C fc( ... )

python f-setup.py应用distutils到运行用Cython,编译和链接:
cython f.pyx -> f.cpp
编译f.cppfc.cpp
链接f.o fc.o- > f.so,一个充满活力的lib了Pythonimport f将加载。

对于学生,我建议:绘制这些步骤的图表,浏览下面的文件,然后下载并运行它们。

distutils是一个庞大,复杂的软件包,用于制作要分发的Python软件包并安装它们。在这里,我们仅使用其中的一小部分进行编译并链接到f.so。这一步骤与Cython无关,但可能会造成混淆;
.pyx中的简单错误可能会导致g ++编译和链接的页面出现模糊的错误消息。另请参阅
distutils的doc 和/或
distutils上的SO问题。)

makesetup.py将重新运行 cython f.pyxg++ -c ... f.cpp 如果f.pyxf.cpp
要清理,rm -r build/

的替代物setup.py将是单独运行的步骤,在脚本或生成文件:
cython --cplus f.pyx -> f.cpp # see cython -h
g++ -c ... f.cpp -> f.o
g++ -c ... fc.cpp -> fc.o
cc-lib f.o fc.o -> dynamic library f.so
修改cc-lib-mac以下针对您的平台和安装的包装器:它不漂亮,但是很小。

有关Cython包装C的真实示例,请查看几乎所有SciKit中的.pyx文件 。

另请参阅:
适用于NumPy用户的Cython
和SO问题/已标记/ cython。

要解压缩以下文件,将其剪切为一个大文件,例如cython-numpy-c-demo,然后在Unix中(在一个干净的新目录中)运行sh cython- numpy-c-demo

#--------------------------------------------------------------------------------
cat >f.pyx <<\!
# f.pyx: numpy arrays -> extern from "fc.h"
# 3 steps:
# cython f.pyx  -> f.c
# link: python f-setup.py build_ext --inplace  -> f.so, a dynamic library
# py test-f.py: import f gets f.so, f.fpy below calls fc()

import numpy as np
cimport numpy as np

cdef extern from "fc.h": 
    int fc( int N, double* a, double* b, double* z )  # z = a + b

def fpy( N,
    np.ndarray[np.double_t,ndim=1] A,
    np.ndarray[np.double_t,ndim=1] B,
    np.ndarray[np.double_t,ndim=1] Z ):
    """ wrap np arrays to fc( a.data ... ) """
    assert N <= len(A) == len(B) == len(Z)
    fcret = fc( N, <double*> A.data, <double*> B.data, <double*> Z.data )
        # fcret = fc( N, A.data, B.data, Z.data )  grr char*
    return fcret

!

#--------------------------------------------------------------------------------
cat >fc.h <<\!
// fc.h: numpy arrays from cython , double*

int fc( int N, const double a[], const double b[], double z[] );
!

#--------------------------------------------------------------------------------
cat >fc.cpp <<\!
// fc.cpp: z = a + b, numpy arrays from cython

#include "fc.h"
#include <stdio.h>

int fc( int N, const double a[], const double b[], double z[] )
{
    printf( "fc: N=%d a[0]=%f b[0]=%f \n", N, a[0], b[0] );
    for( int j = 0;  j < N;  j ++ ){
        z[j] = a[j] + b[j];
    }
    return N;
}
!

#--------------------------------------------------------------------------------
cat >f-setup.py <<\!
# python f-setup.py build_ext --inplace
#   cython f.pyx -> f.cpp
#   g++ -c f.cpp -> f.o
#   g++ -c fc.cpp -> fc.o
#   link f.o fc.o -> f.so

# distutils uses the Makefile distutils.sysconfig.get_makefile_filename()
# for compiling and linking: a sea of options.

# http://docs.python.org/distutils/introduction.html
# http://docs.python.org/distutils/apiref.html  20 pages ...
# https://stackoverflow.com/questions/tagged/distutils+python

import numpy
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
# from Cython.Build import cythonize

ext_modules = [Extension(
    name="f",
    sources=["f.pyx", "fc.cpp"],
        # extra_objects=["fc.o"],  # if you compile fc.cpp separately
    include_dirs = [numpy.get_include()],  # .../site-packages/numpy/core/include
    language="c++",
        # libraries=
        # extra_compile_args = "...".split(),
        # extra_link_args = "...".split()
    )]

setup(
    name = 'f',
    cmdclass = {'build_ext': build_ext},
    ext_modules = ext_modules,
        # ext_modules = cythonize(ext_modules)  ? not in 0.14.1
    # version=
    # description=
    # author=
    # author_email=
    )

# test: import f
!

#--------------------------------------------------------------------------------
cat >test-f.py <<\!
#!/usr/bin/env python
# test-f.py

import numpy as np
import f  # loads f.so from cc-lib: f.pyx -> f.c + fc.o -> f.so

N = 3
a = np.arange( N, dtype=np.float64 )
b = np.arange( N, dtype=np.float64 )
z = np.ones( N, dtype=np.float64 ) * np.NaN

fret = f.fpy( N, a, b, z )
print "fpy -> fc z:", z

!

#--------------------------------------------------------------------------------
cat >cc-lib-mac <<\!
#!/bin/sh
me=${0##*/}
case $1 in
"" )
    set --  f.cpp fc.cpp ;;  # default: g++ these
-h* | --h* )
    echo "
$me [g++ flags] xx.c yy.cpp zz.o ...
    compiles .c .cpp .o files to a dynamic lib xx.so
"
    exit 1
esac

# Logically this is simple, compile and link,
# but platform-dependent, layers upon layers, gloom, doom

base=${1%.c*}
base=${base%.o}
set -x

g++ -dynamic -arch ppc \
    -bundle -undefined dynamic_lookup \
    -fno-strict-aliasing -fPIC -fno-common -DNDEBUG `# -g` -fwrapv \
    -isysroot /Developer/SDKs/MacOSX10.4u.sdk \
    -I/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 \
    -I${Pysite?}/numpy/core/include \
    -O2 -Wall \
    "$@" \
    -o $base.so

# undefs: nm -gpv $base.so | egrep '^ *U _+[^P]'
!

# 23 Feb 2011 13:38


 类似资料:
  • 问题 你想使用Cython来创建一个Python扩展模块,用来包装某个已存在的C函数库。 解决方案 使用Cython构建一个扩展模块看上去很手写扩展有些类似, 因为你需要创建很多包装函数。不过,跟前面不同的是,你不需要在C语言中做这些——代码看上去更像是Python。 作为准备,假设本章介绍部分的示例代码已经被编译到某个叫 libsample 的C函数库中了。 首先创建一个名叫 csample.p

  • 本文向大家介绍cython 包装DLL:从C ++到Cython到Python,包括了cython 包装DLL:从C ++到Cython到Python的使用技巧和注意事项,需要的朋友参考一下 示例 这展示了一个用Cython包装C ++ dll的简单例子。它将涵盖以下主要步骤: 使用Visual Studio使用C ++创建示例DLL。 用Cython包裹DLL,以便可以在Python中调用它。

  • 问题内容: 我想从Python应用程序调用C库。我不想包装整个API,只包装与我的情况相关的函数和数据类型。如我所见,我有三个选择: 在C中创建一个实际的扩展模块。可能有点过头了,我还想避免学习扩展编写的开销。 使用Cython将C库的相关部分公开给Python。 使用Python与外部库进行通信,从而完成整个工作。 我不确定2)还是3)是更好的选择。3)的优点是它是标准库的一部分,并且生成的代码

  • 问题 你想让你写的C代码作为一个C扩展模块来访问,想通过使用 Swig包装生成器 来完成。 解决方案 Swig通过解析C头文件并自动创建扩展代码来操作。 要使用它,你先要有一个C头文件。例如,我们示例的头文件如下: /* sample.h */ #include <math.h> extern int gcd(int, int); extern int in_mandel(double x0,

  • 问题内容: 所以我想通过cython从c调用一些python代码。我设法从c调用cython代码。而且我还可以从cython调用python代码。但是,当我将它们全部加在一起时,会丢失一些东西。 这是我的python代码(): 这是我的cython“ bridge”(): 这是c代码(): 运行此命令时,出现以下异常: 我怀疑缺少的部分: 我还没打电话 我还没有 Cython没有产生任何东西- 不

  • 问题内容: 我有一个接受回调的C ++函数,如下所示: 我想通过给它一个闭包从Cython调用此函数,即,如果我从C ++调用它,我会用lambda来完成。如果这是一个C函数,它将有一些额外的参数: 然后我只想通过的(有更详细的在这里例子)。 有没有办法以C ++的方式做更多的事情,而不必诉诸显式的? 问题答案: 我相信您的目标是将可调用的Python对象传递给接受的对象。您需要创建一些C ++代