通过引用Cython传递一个整数?

时间:2017-10-31 17:28:02

标签: python cython

我正在尝试让一个测试项目工作,调用一个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中传递一个整数参数是行不通的,因为这些参数是不可变的。

2 个答案:

答案 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)

&inttestFn所需)和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)