Как только вы используете int**
(или аналогичный), ваши данные находятся в так называемой косвенной структуре памяти. Представления типизированной памяти Cython поддерживают непрямую компоновку памяти (см., Например, Cython: понимание типизированного представления памяти с раскладкой памяти Indirect_contignuous ), однако не так много классов, реализующих этот интерфейс.
Numpy ndarrays не реализуют косвенную компоновку памяти - они поддерживают только прямую компоновку памяти (например, указатель типа int*
, а не int**
), поэтому передача int**
в массив numpy не принесет пользы.
Хорошо то, что, поскольку вы разделяете память с a_cython
, значения уже были обновлены на месте. Вы можете получить базовый массив numpy, вернув base
-объект представления типизированной памяти, то есть
return a_cython.base # returns 2d-numpy array.
нет необходимости копировать память вообще!
Однако есть некоторые проблемы с управлением памятью (например, вам нужно освободить point_to_a
).
В вашем случае это, возможно, излишество, но я использую возможность без зазрения совести подключить свою библиотеку indirect_buffer
: потому что альтернатив для буферов непрямой разметки памяти мало и время от времени он нужен, я создал его, чтобы не писать всегда один и тот же код.
С indirect_buffer
ваша функция может выглядеть следующим образом:
%%cython
#just an example for a c-function
cdef extern from *:
"""
void fillit(int** ptr, int N, int M){
int cnt=0;
for(int i=0;i<N;i++){
for(int j=0;j<M;j++){
ptr[i][j]=cnt++;
}
}
}
"""
void fillit(int** ptr, int N, int M)
from indirect_buffer.buffer_impl cimport IndirectMemory2D
def py_fillit(a):
#create collection, it is a view of a
indirect_view=IndirectMemory2D.cy_view_from_rows(a, readonly=False)
fillit(<int**>indirect_view.ptr, indirect_view.shape[0], indirect_view.shape[1])
# values are updated directly in a
, который теперь может быть используется, например:
import numpy as np
a=np.zeros((3,4), dtype=np.int32)
py_fillit(a)
print(a)
# prints as expected:
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]])
Вышеупомянутая версия делает многие вещи правильно: управление памятью, блокировка буферов и т. д.