我有一個C函數mallocs()並填充浮點數的二維數組。它「返回」該地址和數組的大小。簽名是我可以強制讓一個numpy ndarray擁有它的內存嗎?
int get_array_c(float** addr, int* nrows, int* ncols);
我想從Python中調用它,所以我使用ctypes的。
import ctypes
mylib = ctypes.cdll.LoadLibrary('mylib.so')
get_array_c = mylib.get_array_c
我從來沒想過如何用ctypes指定參數類型。我傾向於爲我正在使用的每個C函數編寫一個python包裝器,並確保在包裝器中正確地獲取類型。浮點數組是一個列 - 主要順序的矩陣,我想把它作爲numpy.ndarray。但它非常大,所以我想使用C函數分配的內存,而不是複製它。 (我剛剛發現這個PyBuffer_FromMemory東西,在這個StackOverflow的答案:https://stackoverflow.com/a/4355701/3691)
buffer_from_memory = ctypes.pythonapi.PyBuffer_FromMemory
buffer_from_memory.restype = ctypes.py_object
import numpy
def get_array_py():
nrows = ctypes.c_int()
ncols = ctypes.c_int()
addr_ptr = ctypes.POINTER(ctypes.c_float)()
get_array_c(ctypes.byref(addr_ptr), ctypes.byref(nrows), ctypes.byref(ncols))
buf = buffer_from_memory(addr_ptr, 4 * nrows * ncols)
return numpy.ndarray((nrows, ncols), dtype=numpy.float32, order='F',
buffer=buf)
這似乎給我用正確的值的數組。但我很確定這是內存泄漏。
>>> a = get_array_py()
>>> a.flags.owndata
False
該陣列不擁有內存。很公平;默認情況下,當從緩衝區創建數組時,它不應該。但在這種情況下,它應該。當numpy數組被刪除時,我真的很喜歡python爲我釋放緩衝區內存。看起來如果我可以強制owndata爲True,那應該這樣做,但是owndata不可設置。
解決方案不能令人滿意:
使get_array_py的調用者()負責釋放內存。這太煩人了;調用者應該能夠像對待任何其他numpy數組一樣對待這個numpy數組。
在get_array_py中將原始數組複製到一個新的numpy數組中(使用它自己的單獨內存),刪除第一個數組,然後釋放get_array_py()中的內存。返回副本而不是原始數組。這很煩人,因爲它應該是不必要的內存拷貝。
有沒有辦法做我想做的事?我不能修改C函數本身,儘管我可以在庫中添加另一個C函數,如果這有幫助的話。
這聽起來像一個痛苦的世界..我認爲你是要[segfault hell](http://xkcd.com/371/) – wim 2012-01-03 07:27:17
我試過這個以及沒有成功使用ctypes。完整的擴展模塊使這成爲可能,但他們更多的工作來寫。 – 2012-02-01 20:20:25