2012-04-08 5 views
10

Я бы хотел вызвать функцию C из Python, чтобы манипулировать некоторыми массивами NumPy. Функция выглядит так:Обтекание функции C в Cython и NumPy

void c_func(int *in_array, int n, int *out_array); 

где результаты поставляются в out_array, размер которого я знаю заранее (не моя функция, на самом деле). Я пытаюсь сделать в соответствующем .pyx файл следующее, для того, чтобы иметь возможность пройти вход в функцию из массива NumPy, и сохранить результат в виде массива NumPy:

def pyfunc(np.ndarray[np.int32_t, ndim=1] in_array):  
    n = len(in_array) 
    out_array = np.zeros((512,), dtype = np.int32) 
    mymodule.c_func(<int *> in_array.data, n, <int *> out_array.data) 
    return out_array 

Но я получаю "Python objects cannot be cast to pointers of primitive types" ошибка для назначения вывода. Как это сделать?

(Если я требую, чтобы Питон Вызывающий выделяет правильный массив выходной, то я могу сделать

def pyfunc(np.ndarray[np.int32_t, ndim=1] in_array, np.ndarray[np.int32_t, ndim=1] out_array): 
    n = len(in_array) 
    mymodule.cfunc(<int *> in_array.data, n, <int*> out_array.data) 

Но я могу сделать это таким образом, что абонент не имеет предварительно распределить соответствующим образом размерный выходной массив?

+1

пытались ли вы предоставить добавить 'CDEF np.ndarray' перед тем' out_array' присваивания? – Simon

+0

Это работает, спасибо !!! – Peter

ответ

5

Вы должны добавить cdef np.ndarray перед out_array присваивания:

def pyfunc(np.ndarray[np.int32_t, ndim=1] in_array):  
    cdef np.ndarray out_array = np.zeros((512,), dtype = np.int32) 
    n = len(in_array) 
    mymodule.c_func(<int *> in_array.data, n, <int *> out_array.data) 
    return out_array 
0

Вот пример, как манипулировать массивами NumPy с использованием кода, написанного на C/C++ с помощью ctypes. Я написал небольшую функцию в C, взяв квадрат чисел из первого массива и набрав результат второй массив. Число элементов задается третьим параметром. Этот код скомпилирован как общий объект.

squares.c компилируется squares.so:

void square(double* pin, double* pout, int n) { 
    for (int i=0; i<n; ++i) { 
     pout[i] = pin[i] * pin[i]; 
    } 
} 

В питона, вы просто загрузить библиотеку с помощью ctypes и вызовите функцию. Указатели массива получают из интерфейса NumPy ctypes.

import numpy as np 
import ctypes 

n = 5 
a = np.arange(n, dtype=np.double) 
b = np.zeros(n, dtype=np.double) 

square = ctypes.cdll.LoadLibrary("./square.so") 

aptr = a.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) 
bptr = b.ctypes.data_as(ctypes.POINTER(ctypes.c_double)) 
square.square(aptr, bptr, n) 

print b 

Это будет работать для любого C-библиотеки, вы просто должны знать, какие типы аргументов помещаемых, возможно восстановление с-структур в Python с использованием ctypes.

+2

Я думаю, что OP хочет использовать cython, а не ctypes – Simon

Смежные вопросы