【问题标题】:Example program of Cython as Python to C ConverterCython 作为 Python 到 C 转换器的示例程序
【发布时间】:2015-12-27 13:40:08
【问题描述】:

我发现herehere 可以使用 Cython 将 Python 转换为 C,但我找不到任何分步示例。假设我有一个简单的功能:

foo.pyx

cdef void foo(double* x):
   x[0] = 0.0

setup.py

from distutils.core import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize("foo.pyx")
)

然后我运行:python setup.py build_ext --inplace 来获取 foo.c 和 foo.so 文件(以及构建目录)。好吧,我想在 main.c 中使用已翻译(我希望)的 foo 函数。我应该在 main.c 文件中放入什么以及如何编译它才能使用 foo 函数?我正在使用 gcc。

【问题讨论】:

  • 我试过 gcc -L。 -Wall -o main main.c -lpython2.7 -l:foo.so,但我认为我在 main.c 文件中遗漏了一些东西,因为我得到“未定义的对 `foo' 的引用”
  • 你想从 main.c 调用 foo 吗?喜欢docs.cython.org/src/userguide/…?
  • @PadraicCunnigham 没错!我想要 foo(x) 调用。
  • 那么,我只需要添加 api 关键字就可以了?我应该检查一下。
  • 对不起@PadraicCunningham 但我不知道如何编译它。我包括了“foo_api.h”和 import_foo() 但我得到了分段错误

标签: python c cython


【解决方案1】:

远非 c 专家,但对使用 ubuntu 的我来说,以下工作:

main.c:

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


int main(int argc, char *argv[]) {
     Py_Initialize();
     initfoo();
     import_foo();
     double arr[5] = {1,2,3,4,5};
     int i = 0;
     foo(arr);
     for(i = 0; i < 5; i++)
    {
      printf("%f\n", arr[i]);
    }
     Py_Finalize();
     return 0;
}

foo.pyx:

cdef public api  foo(double* x):
   x[0] = 0.0

来自同一目录:

$ cython foo.pyx 

然后:

$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o foo  *.c -lpython2.7 

然后运行。

$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000

我使用pkg-config --cflags python 来获取标志:

 $ pkg-config --cflags python
-I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7 

不调用Py_Initialize初始化 Python 解释器。在嵌入 Python 的应用程序中,应在使用任何其他 Python/C API 函数之前调用它;),您将获得:

Fatal Python error: PyThreadState_Get: no current thread
Aborted (core dumped)

没有initfoo()import_foo() 你会得到:

 Segmentation fault (core dumped)

如果你不打电话给Py_Finalize

Py_Initialize 第二次调用时无操作(没有先调用 Py_Finalize())。

要从文档中获取 delorean 示例以运行:

main.py:

#include "delorean_api.h"
#include <stdio.h>
Vehicle car;


int main(int argc, char *argv[]) {
     Py_Initialize();
     initdelorean();
     import_delorean();
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     activate(&car);
     Py_Finalize();
     return 0;
}

delorean.pyx:

ctypedef public struct Vehicle:
    int speed
    float power

cdef api void activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        print "Time travel achieved"
    else:
        print("Sorry Marty")

过程是一样的,唯一的变化是我必须在 Vehicle struct 中使用 ctypedef 或者在 main 中使用我必须在 main 中使用 struct Vehicle car;

$ cython delorean.pyx
$ cc  -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o delorean  *.c -lpython2.7  
$ ./delorean 1 1
Sorry Marty
$ ./delorean 100 2
Time travel achieved

您也可以在不使用Py_Initialize 等的情况下使其工作...

foo.pyx 中你只需要将函数公开:

cdef public  foo(double* x):
   x[0] = 0.0

我在 main.c 中添加了 #include &lt;python2.7/Python.h&gt; 刚刚导入 foo.h 并删除了 Py_Initialize(); 等。仅导入 python.h 对我不起作用,但可能并非对每个人都适用。

#include <python2.7/Python.h>
#include "foo.h"
#include <stdio.h>


int main(int argc, char *argv[]) {
     double arr[5] = {1,2,3,4,5};
     int i = 0;
     foo(arr);
     for(i = 0; i < 5; i++)
    {
      printf("%f\n", arr[i]);
    }

     return 0;
}

编译是一样的:

$ cython foo.pyx 
$ cc -I/usr/include/python2.7 -I/usr/include/x86_64-linux-gnu/python2.7   -o foo  *.c -lpython2.7 
$ ./foo
0.000000
2.000000
3.000000
4.000000
5.000000

如果您使用的是 api 版本,则只需根据文档包含 api 标头,反之亦然否则你可能会得到相互冲突的双重定义。

要对 delorean 示例执行相同操作,我必须使用 libc.stdio 打印字符串以避免分段错误:

from libc.stdio cimport printf

ctypedef public  struct Vehicle:
    int speed
    float power

cdef public void activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        printf("Time travel achieved\n")
    else:
        printf("Sorry Marty\n")

主要:

#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"

Vehicle car;


int main(int argc, char *argv[]) {
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     activate(&car);
     return 0;
}

返回值可能更有意义:

ctypedef public  struct Vehicle:
    int speed
    float power

cdef public  char* activate(Vehicle *v):
    if v.speed >= 88 and v.power >= 1.21:
        return  "Time travel achieved"
    return "Sorry Marty"

主要:

#include <python2.7/Python.h>
#include <stdio.h>
#include "delorean.h"

Vehicle car;

int main(int argc, char *argv[]) {
     car.speed = atoi(argv[1]);
     car.power = atof(argv[2]);
     printf("%s\n",activate(&car));
     return 0;
}

【讨论】:

  • 感谢您的回答@PadraicCunningham。我虽然可以完全按照 delorean 示例解决这个 Py_Initialize() 等问题。
  • 不错@PadraicCunningham :)
  • 你知道如何处理像 e.g. 这样的库吗? numpy,mpmath,scipy?我试图添加 import numpy as np 并返回 np.exp(2.0) 但我使用没有 api 字的第二种方法得到了分段错误(仅限公共)。
  • @Bociek,你用哪个试过return np.exp(2.0)
  • 在 .pyx 文件中我写道:import numpy as np; cdef public double foo(double x): return np.exp(2.0)。主要我只有 #include 和 #include "foo.h"
猜你喜欢
  • 2011-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-30
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 2011-06-06
相关资源
最近更新 更多