2013-06-09 10 views
7

Piszę wrapper Cythona do funkcji C. Mam plik PXD z następującym podpisem:Cython: nie można przekonwertować obiektu Pythona na "double *"

double contr_hrr(int lena, double xa, double ya, double za, double *anorms) 

Kiedy próbuję wywołać ten z pliku pyx

... 
return contr_hrr(len(acoefs),a.origin[0],a.origin[1],a.origin[2],anorms2) 

gdzie anorms2 jest lista Python, pojawia się komunikat o błędzie:

cython/ctwo.pyx:35:80: Cannot convert Python object to 'double *' 

Jak przekazać listę Pythona do funkcji C jako podwójnej tablicy?

+0

Jeśli masz okazję przetestować różne metody, byłbym bardzo zainteresowany wiedząc, który jest najszybszy ... –

+0

@Golgauth - Na pewno spróbuję. Kod jest 2 razy wolniejszy niż stara metoda, w której bezpośrednio owinąłam procedury C używając C. – Rick

+0

Jakie było twoje ostatnie podejście? Być może możesz napisać własną odpowiedź na ten temat ... –

Odpowiedz

5
  1. cimport array:

    from cpython cimport array 
    
  2. Utwórz obiekt array z listy. konstruktor klasy tablic wykona całą pamięć alokującą i przechodząc przez twoją listę (może być faktycznie iterowalna).

    cdef array.array anorms2_arr = array.array('d', anorms2) 
    
  3. Przełóż swoje dane do funkcji:

    return contr_hrr(.., anorms2_arr.data.as_doubles) 
    

array jest standard Python module. Cython dodaje specjalne wsparcie, takie jak interfejs bufora i bezpośredni dostęp do podstawowego bloku pamięci przez arr.data.as_xxx. Niestety, ta pomoc jest tylko udokumentowana here. Możesz także znaleźć pewne szczegóły dotyczące użycia macierzy w this recent thread.

+0

Jak aktualne są rzeczy z tablicy? Dostaję "cython/ctwo.pyx: 3: 0:" array.pxd "nie znaleziono" kiedy próbuję cimportować tablicę. – Rick

+0

@Rick Właśnie sprawdziłem wydanie 0.19.1 (ostatnie) stabilne, a plik tam był. Przetestowałem także import z moją obecną wersją '0.18': to działało dobrze dla mnie ... Cóż, co jest twoje? –

+0

Został dodany w [Cython 0.17] (http://wiki.cython.org/ReleaseNotes-0.17). Najnowsza wersja jest zazwyczaj najlepsza. –

3

myślę, że nie można zrobić inaczej, ale przekształcić go samemu:

cimport cython 
from libc.stdlib cimport malloc, free 

... 
cdef double *anorms 
cdef unsigned int i; 

anorms = <double *>malloc(len(anorms2)*cython.sizeof(double)) 
if anorms is NULL: 
    raise MemoryError() 

for i in xrange(len(anorms2)): 
    anorms[i] = anorms2[i] 

return contr_hrr(len(acoefs),a.origin[0],a.origin[1],a.origin[2],anorms) 

Gdybyś był w C++, to byłaby inna, ponieważ

The following coercions are available: 
Python type => C++ type    => Python type 
bytes    std::string    bytes 
iterable   std::vector    list 
iterable   std::list    list 
iterable   std::set    set 
iterable (len 2) std::pair    tuple (len 2) 

Jeśli można przełączyć się C++, czy masz bezpośrednie tłumaczenie z List[float] do vector<double>:

from libcpp.vector cimport vector 

def py_contr_hrr(vector[double] anorms2, ...): 
    ... 
    return contr_hrr(len(acoefs),a.origin[0],a.origin[1],a.origin[2],anorms2) 

i wywołanie bezpośrednio ze strony Pythona:

anorms2 = [12.0, 0.5, ...] 
py_contr_hrr(anorms2, ....) 

Źródło: http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#standard-library

Ale ja nie wiem, czy to jest opcja, że ​​można rozważyć ... To zależy od ograniczeń Twojego projektu, oczywiście .

EDYCJA: Nie wiedziałem o sposobie wykonania Nikita (który jest elegancki, nawiasem mówiąc), i nie znam eteru, który jest najlepszy w odniesieniu do występów na dużych tablicach.

+0

Dziękuję bardzo za wpis. W tej chwili próbuję Nikity, a jeśli to nie zadziała, spróbuję tego. – Rick

+0

Tak, wygląda dobrze. –

2

W końcu udało mi się upewnić, że tablice anorms były utrzymywane w postaci tablic w pythonowej części kodu, a następnie zgodnie z przepisem Nikity, aby przekonwertować je w locie na podwójne za pomocą właściwości .data.as_doubles.Jeśli to zrobię, wydaje się, że ma bardzo mały narzut w porównaniu do robienia wszystkiego natywnie w C.

Jeszcze nie eksperymentowałem z podejściem numpy, z różnych przyziemnych powodów.

+0

Ok, dzięki za udostępnienie ;-) –