Prototypowanie kodu Pythona przed kompilacją

Rozmyślałem nad napisaniem biblioteki Peak fitting przez jakiś czas. Znam Pythona dość dobrze i planuję zaimplementować wszystko w Pythonie na początku, ale przewiduję, że być może będę musiał ponownie zaimplementować niektóre podstawowe procedury w skompilowanym języku.

IIRC, jeden z oryginalnych remitów Pythona był językiem prototypowym, jednak Python jest dość liberalny w pozwalaniu funkcjom, funkcjom, obiektom na przekazywanie funkcji i metod, podczas gdy podejrzewam, że to samo nie jest prawdą w przypadku powiedz C lub Fortran.

Co powinienem wiedzieć o projektowaniu funkcji/klas, które przewiduję, że będą miały interfejs do skompilowanego języka? I ile z tych potencjalnych problemów rozwiązują biblioteki takie jak cTypes, bgen, SWIG, Boost.Python, Cython czy Python SIP ?

W tym konkretnym przypadku użycia, (biblioteka dopasowania) wyobrażam sobie, pozwalając użytkownikom definiować funkcje matematyczne (Guassian, Lorentzian itp.) jako funkcje Pythona, które może być następnie przekazana interpretowana przez skompilowaną bibliotekę dopasowania kodu. Przekazywanie i zwracanie tablic jest również niezbędne.

Author: Mike Pennington, 2008-08-19

7 answers

Wreszcie pytanie, na które naprawdę mogę odpowiedzieć:).

Zbadałem f2py, boost.python, swig, cython i pyrex za pracę doktorską z optycznych technik pomiarowych. Używałem swig intensywnie, boost.python trochę i pyrex i cython dużo. Używałem też ctypów. To jest moje załamanie:

Disclaimer: to jest moje osobiste doświadczenie. Nie jestem zaangażowany w żaden z tych projektów.

Swig: nie gra dobrze z c++. Powinno, ale nazwa w Linuksie i Mac OS X problemy z linkowaniem były dla mnie bardzo bolesne. jeśli masz kod C i chcesz, aby był połączony z Pythonem, jest to dobre rozwiązanie. Owinąłem GTS dla moich potrzeb i musiałem napisać w zasadzie bibliotekę współdzieloną C, z którą mógłbym się połączyć. Nie polecam.

Ctypes: Napisałem wrapper libdc1394 (IEEE Camera library) używając ctypes i było to bardzo proste doświadczenie. Kod znajdziesz na https://launchpad.net/pydc1394 . konwersja nagłówków na kod Pythona wymaga dużo pracy, ale wtedy wszystko działa niezawodnie. Jest to dobry sposób, jeśli chcesz połączyć zewnętrzną bibliotekę. Ctypes jest również w stdlib Pythona, więc każdy może użyć Twojego kodu od razu. Jest to również dobry sposób na szybką zabawę z nową lib w Pythonie. Mogę polecić go do interfejsu do zewnętrznych bibliotek.

Boost.Python : bardzo przyjemne. Jeśli posiadasz już własny kod C++ że chcesz użyć w Pythonie, idź na to. W ten sposób bardzo łatwo jest przetłumaczyć struktury klas c++ na struktury klas Pythona. Polecam, jeśli masz kod c++, który potrzebujesz w Pythonie.

Pyrex / Cython: Użyj Cythona, nie Pyrexa. Kropka. Cython jest bardziej zaawansowany i przyjemniejszy w użyciu. W dzisiejszych czasach robię wszystko z cythonem, co kiedyś robiłem z SWIG lub Ctypes. Jest to również najlepszy sposób, jeśli masz kod Pythona, który działa zbyt wolno. Proces jest absolutnie fantastyczny: ty Konwertuj Moduły Pythona na moduły cython, buduj je i profiluj i optymalizuj tak, jakby wciąż był Pythonem(bez konieczności zmiany narzędzi). Następnie możesz zastosować jak najwięcej (lub tak mało) kodu C zmieszanego z kodem Pythona. Jest to o wiele szybsze niż konieczność przepisania całych części aplikacji w C; przepisujesz tylko wewnętrzną pętlę.

Timings: ctypes ma najwyższy wynik wywołania (~700ns), po którym następuje boost.Pythona( 322ns), a następnie bezpośrednio przez swig (290ns). Cython ma najniższy koszt połączenia (124ns) i najlepsza informacja zwrotna, na której spędza czas (wsparcie cProfile!). Liczby są z mojej skrzynki wywołującej trywialną funkcję, która zwraca liczbę całkowitą z interaktywnej powłoki; importowanie modułów nie jest zatem timed, tylko wywołanie funkcji jest overhead. Dlatego też najprostszym i najbardziej produktywnym jest szybkie uzyskanie kodu Pythona poprzez profilowanie i używanie cythona.

Summary: dla Twojego problemu użyj Cythona ;). Mam nadzieję, że to podsumowanie będzie przydatne dla niektórych osób. Chętnie odpowiem na każde pytanie.


Edit : zapomniałem wspomnieć: dla celów numerycznych (czyli połączenia z NumPy) używać Cythona; mają dla niego wsparcie (ponieważ w zasadzie rozwijają cython do tego celu). Więc to powinno być kolejne +1 dla twojej decyzji.

 35
Author: SirVer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-02 13:49:49

Nie używałem SWIG ani SIP, ale znajduję pisanie wrapperów Pythona z boost.python jest bardzo wydajny i stosunkowo łatwy w użyciu.

Nie jestem pewien, jakie są Twoje wymagania dotyczące przekazywania typów między C/C++ a Pythonem, ale możesz to łatwo zrobić, wystawiając Typ C++ na Pythona lub używając ogólnego argumentu boost::python::object do swojego API C++. Możesz także zarejestrować Konwertery, aby automatycznie konwertować typy Pythona na typy C++ i vice versa.

Jeśli planujesz użyć boost.python, tutorial jest dobrym miejscem do rozpoczęcia.

Zaimplementowałem coś podobnego do tego, czego potrzebujesz. Mam funkcję C++, która przyjmuje funkcję Pythona i obraz jako argumenty i stosuje funkcję Pythona do każdego piksela obrazu.

Image* unary(boost::python::object op, Image& im)
{
    Image* out = new Image(im.width(), im.height(), im.channels());
    for(unsigned int i=0; i<im.size(); i++)
    {
        (*out)[i] == extract<float>(op(im[i]));
    }
    return out;
}

W tym przypadku obraz jest obiektem C++ wystawionym na działanie Pythona( obraz z pikselami zmiennoprzecinkowymi), a op jest funkcją zdefiniowaną przez Pythona (a właściwie dowolnym obiektem Pythona z wywołaniem _ ___ atrybut). Następnie możesz użyć tej funkcji w następujący sposób (zakładając, że uniary znajduje się w wywołanym obrazie, który zawiera również obraz i funkcję load):

import image
im = image.load('somefile.tiff')
double_im = image.unary(lambda x: 2.0*x, im)

Jeśli chodzi o używanie tablic z boostem, osobiście tego nie robiłem, ale wiem, że dostępna jest funkcja wystawiania tablic pythonowi za pomocą boost - to może być pomocne.

 10
Author: Moe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-26 16:48:13

Najlepszym sposobem na zaplanowanie ewentualnego przejścia na skompilowany kod jest napisanie wrażliwych na wydajność części jako modułu prostych funkcji w stylu funkcjonalnym (bezstanowym i bez efektów ubocznych), które akceptują i zwracają podstawowe typy danych.

Zapewni to mapowanie jeden-do-jednego z kodu prototypu Pythona na ewentualny skompilowany kod, i pozwoli Ci łatwo używać ctypes i uniknąć wielu bólów głowy.

Do montażu szczytowego, będziesz prawie na pewno trzeba korzystać z tablic, co trochę komplikuje sprawy, ale nadal jest bardzo wykonalne z ctypes.

Jeśli naprawdę chcesz użyć bardziej skomplikowanych struktur danych lub zmodyfikować przekazane argumenty, SWIGlub standardowy interfejs Pythona C-extension pozwoli Ci robić to, co chcesz, ale z pewną ilością kłopotów.

Za to, co robisz, możesz również sprawdzić NumPy , które mogą wykonać część pracy, którą chcesz wcisnąć do C, jako oprócz zaoferowania dodatkowej pomocy w przenoszeniu danych pomiędzy Pythonem A C .

 6
Author: Jason Pratt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 01:46:40

F2py (część numpy) jest prostszą alternatywą dla SWIG i boost.python do owijania kodu C / Fortran.

 4
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-29 22:30:59

Z mojego doświadczenia wynika, że istnieją dwa proste sposoby wywoływania kodu C z kodu Pythona. Istnieją inne podejścia, z których wszystkie są bardziej irytujące i / lub gadatliwe.

Pierwszym i najłatwiejszym jest skompilowanie kodu C jako oddzielnej biblioteki współdzielonej, a następnie wywołanie funkcji w tej bibliotece za pomocą ctypes. Niestety przekazywanie czegokolwiek innego niż podstawowe typy danych jest nietrywialne.

Drugim najprostszym sposobem jest napisanie modułu Pythona w języku C, a następnie wywołanie funkcji w tym module. Możesz przekazać wszystko, co chcesz do tych funkcji C bez konieczności przeskakiwania przez obręcze. I łatwo jest wywoływać funkcje lub metody Pythona z tych funkcji C, jak opisano tutaj: https://docs.python.org/extending/extending.html#calling-python-functions-from-c

Nie mam wystarczającego doświadczenia z SWIG, aby oferować inteligentny komentarz. Podczas gdy możliwe jest przekazywanie niestandardowych obiektów Pythona do funkcji C poprzez ctypes lub definiowanie nowych klas Pythona w C, te rzeczy są irytujące i gadatliwe i polecam podjęcie jednego z dwóch podejść opisanych powyżej.

 1
Author: Eli Courtwright,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-14 01:47:04

Python jest dość liberalny w zezwalaniu funkcjom, funkcjom, obiektom na przekazywanie funkcji i metod, podczas gdy podejrzewam, że to samo nie dotyczy np. C czy Fortran.

W C nie można przekazać funkcji jako argumentu do funkcji, ale można przekazać wskaźnik funkcji, który jest tak samo dobry jak funkcja.

Nie wiem, jak bardzo by to pomogło, gdy próbujesz zintegrować kod C i Pythona, ale chciałem tylko wyjaśnić jedno błędne przekonanie.

 0
Author: David Locke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-29 22:52:19

Oprócz powyższych narzędzi, mogę polecić użycie Pyrex (do tworzenia modułów rozszerzeń Pythona) lub Psyco (jako kompilator JIT dla Pythona).

 0
Author: Roman Zeyde,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-16 15:08:53