我正在尝试让一个测试项目工作,调用一个C函数,需要通过引用传递一个整数参数,来自Python:
TEST.CPP :
#include <iostream>
using namespace std;
void testFn(int &val);
void testFn(int &val)
{
cout << "val: " << val << endl;
val = -1;
}
caller.pyx :
cdef extern from "test.cpp":
void testFn(int &val)
def myTest(int[:] val):
testFn(&val[0])
def main():
val = [0];
myTest(val)
print(val)
setup.caller.py :
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
sourcefiles = ['caller.pyx']
ext_modules = [Extension("caller", sourcefiles)]
setup(
name = 'test app',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
但是当我尝试构建项目时,我收到一个错误:
$ python setup.caller.py build_ext --inplace
Compiling caller.pyx because it changed.
[1/1] Cythonizing caller.pyx
Error compiling Cython file:
------------------------------------------------------------
...
def myTest(int[:] val):
testFn(&val[0])
^
------------------------------------------------------------
caller.pyx:11:20: Cannot assign type 'int *' to 'int'
据我所知,在Python中传递一个整数参数是行不通的,因为这些参数是不可变的。
答案 0 :(得分:2)
正如错误所说:你传递一个指针,它指向普通类型(C ++实际上不像指针一样 - 它们不能被解引用等)。我认为以下内容应该有效:
def myTest(int[:] val):
testFn(val[0])
由于list不是缓冲区类型,因此main
函数也会出现问题(因此不能与memoryview一起使用)。通过将其转换为numpy数组或Python数组来修复它
def main():
val = np.array([0],dtype=np.int) # or array.array
myTest(val)
print(val)
答案 1 :(得分:1)
&int
(testFn
所需)和int *
(您的&val[0]
)不完全相同,这解释了编译器错误。
即使可以就地更改python-integer,也不应该这样做。一种可能的解决方案是将python-integer传递给包装函数,并将包装函数的结果作为新的python-integer返回:
def myTest(int val):
testFn(val)
return val
在幕后,cython将python-integer转换为c样式的整数,并在调用myTest
之后将其转换为(新的)python-integer。但是,val
是一个独立的(本地)变量,而不是对原始python整数的引用,因此通过更改它我们不会更改原始:
>>> a=6
>>> b=myTest(a)
val: 6
>>> a,b
(6,-1)