2013-05-08 13 views
6

Alcune funzioni di SciPy (come scipy.ndimage.interpolation.geometric_transform) possono utilizzare i puntatori alle funzioni C come argomenti per evitare di chiamare un oggetto chiamabile in Python su ciascun punto dell'array di input.Creazione di un puntatore PyCObject in Cython

In sintesi:

  • definire una funzione denominata my_function qualche parte del modulo C
  • Return un PyCObject con il puntatore &my_function e (facoltativamente) un puntatore void* per passare alcuni dati globali intorno

Il metodo API correlato è PyCObject_FromVoidPtrAndDesc ed è possibile leggere Extending ndimage in C per vederlo in azione.

Sono molto interessato all'utilizzo di Cython per mantenere il mio codice più gestibile, ma non sono sicuro di come esattamente dovrei creare un tale oggetto. Qualsiasi, bene, ... puntatori?

+2

+1 solo per lo scherzo del puntatore :-p – Will

+0

Sembrava la cosa giusta da fare! : D –

risposta

1

Basta fare in Cython la stessa cosa si dovrebbe fare in C, chiamare PyCObject_FromVoidPtrAndDesc direttamente. Ecco un esempio del tuo collegamento portato a Cython:

###### example.pyx ###### 

from libc.stdlib cimport malloc, free 
from cpython.cobject cimport PyCObject_FromVoidPtrAndDesc 

cdef int _shift_function(int *output_coordinates, double* input_coordinates, 
      int output_rank, int input_rank, double *shift_data): 
    cdef double shift = shift_data[0] 
    cdef int ii 
    for ii in range(input_rank): 
     input_coordinates[ii] = output_coordinates[ii] - shift 
    return 1 

cdef void _shift_destructor(void* cobject, void *shift_data): 
    free(shift_data) 

def shift_function(double shift): 
    """This is the function callable from python.""" 
    cdef double* shift_data = <double*>malloc(sizeof(shift)) 
    shift_data[0] = shift 
    return PyCObject_FromVoidPtrAndDesc(&_shift_function, 
             shift_data, 
             &_shift_destructor) 

Le prestazioni devono essere identiche alla versione C pura.

Si noti che Cyhton richiede l'operatore & per ottenere l'indirizzo della funzione. Inoltre, a Cython manca l'operatore di dereferenziazione puntatore *, viene invece utilizzato l'equivalente di indicizzazione (*ptr ->ptr[0]).

+0

Grazie per il corretto 'cimport's! Dopo un po ', stavo pensando di importare le funzioni dal file '.h' e fare grosso modo lo stesso, ma non ero sicuro di come gestire riferimenti e dereferenze, quindi il tuo esempio cancella tutto in un colpo solo;) –

0

Penso che sia una cattiva idea. Cython è stato creato per evitare di scrivere anche PyObjects! Inoltre, in questo caso, la scrittura del codice attraverso Cython probabilmente non migliora il codice di manutenzione ... Ad ogni modo, è possibile importare il PyObject con

from cpython.ref cimport PyObject 

nel codice Cython.

UPDATE

from cpython cimport * 

è più sicuro.

Cheers, Davide

+1

Si potrebbe notare che ho scritto ** 'PyCObject' ** e non' PyObject'. Un 'PyObject' è un normale oggetto Python, mentre un' PyCObject' è uno speciale 'PyObject' usato per contenere puntatori opachi agli indirizzi di memoria grezza. È usato, come ho detto, da alcune funzioni in SciPy, che recuperano semplicemente il puntatore alla funzione da 'PyCObject' e lo usano senza il sovraccarico di chiamare un vero metodo Python. ;) –

Problemi correlati