问题描述
我正在通过cython包装一个c ++程序,并希望在Python中提供该程序的矢量。
我已经为向量编写了一个getter方法,除了返回数据的副本之外,它的工作原理还不错:
# in cython
from libcpp.vector cimport vector
cimport numpy as np
cdef np.ndarray[double] vector_to_double_arr(vector[double] vec):
cdef double[::1] arr = <double [:vec.size()]>vec.data()
return np.asarray(arr)
def get_variable()
return vector_to_double_arr(my_c_vector) # my_c_vector is a global variable defined elsewhere
也就是说,在python中,对返回数组的赋值无效,因为该值仅分配给副本。
# in python
get_variable()[0] = 4 # has no effect
过去,我通过先创建numpy数组并在内部数据上使用c ++进行操作来解决此问题。但是,现在我必须处理一个预先存在的向量。
我已经考虑过直接返回memoryview:
cdef np.ndarray[double] vector_to_double_arr(vector[double] vec):
cdef double[::1] arr = <double [:vec.size()]>vec.data()
return arr
但是,我还没有弄清楚如何使memoryview在Python中显示为数组。我需要一些包装此memoryview的对象,并可以适当的方式对其进行写入。我当时在考虑创建一个numpy数组并将其分配给np.ndarray.data
属性,但是写入该数组是一种不好的做法,而且行不通。
如何从Python写入c ++向量?作为扩展:如果我不处理向量而是双精度数组,该怎么办?
我现在已经通过复制代码实现了the solution suggested by @ead:
from libc.stdlib cimport free
from cpython.object cimport PyObject
from cpython.ref cimport Py_INCREF
np.import_array()
cdef class MemoryNanny:
cdef void* ptr # set to NULL by "constructor"
def __dealloc__(self):
print("freeing ptr=",<unsigned long long>(self.ptr)) #just for debugging
free(self.ptr)
@staticmethod
cdef create(void* ptr):
cdef MemoryNanny result = MemoryNanny()
result.ptr = ptr
print("nanny for ptr=",<unsigned long long>(result.ptr)) #just for debugging
return result
cdef extern from "numpy/arrayobject.h":
# a little bit awkward: the reference to obj will be stolen
# using PyObject* to signal that Cython cannot handle it automatically
int PyArray_SetBaSEObject(np.ndarray arr,PyObject *obj) except -1 # -1 means there was an error
cdef array_from_ptr(void * ptr,np.npy_intp N,int np_type):
cdef np.ndarray arr = np.PyArray_SimpleNewFromData(1,&N,np_type,ptr)
nanny = MemoryNanny.create(ptr)
Py_INCREF(nanny) # a reference will get stolen,so prepare nanny
PyArray_SetBaSEObject(arr,<PyObject*>nanny)
return arr
然后按如下方式访问指针:
cdef MyClass()
...
@property
def myArray(self):
return array_from_ptr(myArrayPointer,myArrayPointerLength,np.NPY_FLOAT64)
从Python访问该属性效果很好,但是,一旦我更改了数组中的任何值(同样起作用),程序就会暂停。
m = MyClass()
print(m.myArray) # prints what it is supposed to print
m.myArray[0] = 1 # works
print(m.myArray) # prints what is expected,but terminates the program after freeing the freeing the pointer.
...
当我删除上面代码块中的最后一个打印语句时,一切仍然正常。为什么?我很困惑。我该怎么做才能解决问题?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)