Cython:从 C 程序调用 Python 代码
Posted
技术标签:
【中文标题】Cython:从 C 程序调用 Python 代码【英文标题】:Cython: Calling Python code from C program 【发布时间】:2014-01-07 01:13:58 【问题描述】:我正在尝试制作 Cython 包装器,以便我可以从 C 调用 Python 代码。我遇到了导入问题,因为我希望包装器与原始代码分开。
以下代码在调用导入函数时以 segfault 结尾。如果代码被编写为 python 模块并通过import
导入,则程序会说name ... is not defined
。当所有内容都在一个文件中并且不涉及导入时,问题不会出现(实际上,Cython 生成的代码在 cimporting 时会失败)。当从其他 python 脚本(编译为 .so 或实时)导入 libcimpy.pyx 时,代码也可以正常工作
我准备了一个最小的例子。这与实际代码相去甚远,但涵盖了原理。
cimpPy.pyx:示例 python 代码(转换为 Cython)
cdef sum(a, b):
return a + b
cimpPy.pxd
cdef sum(a, b)
libcimpy.pyx(粘贴 Cython 代码)
cimport cimpPy
cdef public int cSum(int a, int b):
return cimpPy.sum(a, b)
ci.c(我们要从中调用 cimpPy 的 c 代码)
#include <stdio.h>
#include <stdlib.h>
#include <Python.h>
#include "libcimp.h"
int main(int argc, char **argv)
Py_Initialize();
initlibcimp();
int a = 2;
int b = 3;
int c = cSum(a, b);
printf("sum of %d and %d is %d\n", a, b, c);
Py_Finalize();
return 0;
生成文件
EXECUTABLE = ci
OBJS = ci.o
CC = gcc
CFLAGS = -g -I/usr/include/python2.7 -I$(shell pwd)
LINKER = g++
LDFLAGS = -L$(shell pwd) $(shell python-config --ldflags) -lcimp
.PHONY: clean cython
all: cython $(EXECUTABLE)
cython:
python setup.py build_ext --inplace
.c.o:
$(CC) $(CFLAGS) -c $<
$(EXECUTABLE) : $(OBJS)
$(LINKER) -o $(EXECUTABLE) $(OBJS) $(LDFLAGS)
clean:
rm -rf *.o *.so libcimp.c libcimp.h core build $(EXECUTABLE)
setup.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
extensions = [
Extension("libcimp", ["libcimp.pyx"])
]
setup(
name = "CIMP",
cmdclass = "build_ext": build_ext,
ext_modules = cythonize(extensions)
)
我打算实现的是能够将 Python 代码插入到更大的 C 系统中。假设是用户将能够自己编写 Python。 C 代码是一个模拟引擎,可以在环境中对代理进行操作。这个想法是代理和环境的行为可以在 python 中指定,并在必要时传递给引擎进行评估。最好的类比是一个 map reduce 系统,其中 Python 脚本是映射器。从这个意义上说,我想从 C 调用 Python,而不是反过来。
将所有内容都转换为 Cython,而引人注目的是大型任务。
这是正确的方法吗?为什么导入仅在 python 解释器下有效,而在外部嵌入时无效?任何建议和参考文章或文档表示赞赏。
【问题讨论】:
docs.python.org/2/extending/… 回复“这是正确的做法吗?”,试图澄清情况。如果您打算让用户使用 Python 编写代码,并为您的 C 模拟引擎提供 Python 接口,那么您正在做相反的事情。上面,您正在尝试从 C 接口 Python 代码,反之亦然。正如您所说,如果您想“将 Python 代码插入到更大的 C 系统中”,那就可以了。但是如果你想为引擎创建一个接口,以便用户可以用python对其进行编程,你想从python调用c,而不是从c调用python。 @flebool 在您回复后我意识到我对我想要实现的目标提供了不太好的解释。 C 代码是一个模拟引擎,可以在环境中对代理进行操作。这个想法是在 python 中指定代理和环境的行为,并在必要时传递给引擎进行评估。最好的类比是一个 map reduce 系统,其中 Python 脚本是映射器。从这个意义上说,我想从 C 调用 Python,而不是反过来。 【参考方案1】:在这段代码中,initlibcimp()
实际上是失败的,但是你并没有马上看到,因为错误是通过设置python异常来报错的。我不是 100% 确定这是执行此操作的正确方法,但我可以通过在该调用下方添加以下代码来查看错误:
if (PyErr_Occurred())
PyErr_Print();
exit(-1);
然后,程序会输出:
Traceback (most recent call last):
File "libcimpy.pyx", line 1, in init libcimpy (libcimpy.c:814)
cimport cimpPy
ImportError: No module named cimpPy
cimpPy
模块尚未定义的原因是您需要在调用initlibcimp
之前调用initcimpPy()
。
【讨论】:
以上是关于Cython:从 C 程序调用 Python 代码的主要内容,如果未能解决你的问题,请参考以下文章
使用 python-c-api 调用的 Cython 回调段错误