Jak używać Rusta z Pythonem, a Pythona z Rustem

Możesz połączyć wygodę Pythona z szybkością Rusta, dzięki bibliotekom w obu językach. Zacznij od projektu PyO3 i skrzynki cpython.

Matthew Lancaster / Flickr

Python i Rust zajmują pozornie przeciwległe końce spektrum języków. Python, interpretowany w czasie rzeczywistym, oferuje programistom elastyczne i wygodne środowisko programowania, ale kosztem surowej prędkości. Rust zapewnia szybkość, plus gwarancje bezpieczeństwa pamięci, ale wymaga nauczenia się nowego paradygmatu obsługi operacji pamięciowych. W teorii, te języki nie powinny konkurować, powinny współpracować. W praktyce mogą. Rust może skorzystać z łatwości użycia Pythona, a Python może skorzystać z szybkości i bezpieczeństwa Rusta.

Jeśli chcemy używać Rust z Pythonem lub Pythona z Rustem, musimt mieć przynajmniej przelotną znajomość obu języków, aby uzyskać najlepsze rezultaty. Musimy również zdecydować, który z nich jest naszym głównym językiem, ponieważ opcje dla każdego podejścia są znacząco różne.

Zobacz również:

  • Rust ma nową, wspierającą go radę
  • Premiera GitHub Copilot Enterprise

Wywoływanie Rusta z Pythona za pomocą PyO3

Jeśli Python jest naszym podstawowym językiem, integracja z Rustem działa koncepcyjnie w taki sam sposób, jak integracja Pythona z C. Domyślna implementacja Pythona, napisana w C, używa rozszerzeń napisanych w C lub używających ABI zgodnego z C. Rozszerzenia napisane w języku Rust, które używają tego samego ABI, również będą działać, chociaż nie jest to automatyczne - trzeba użyć skrzynek zaprojektowanych w celu zapewnienia wiązań dla funkcji Rust do API Pythona C.

Tworzenie wiązań Rust w Pythonie

Najbardziej znanym projektem do tworzenia wiązań Rust w Pythonie jest PyO3. Można go użyć do pisania modułów Pythona w Rust lub do osadzenia runtime’u Pythona w binarce Rust.

PyO3 wykorzystuje inny projekt, Maturin, który jest narzędziem do tworzenia skrzynek Rust z opakowaniami i wiązaniami Pythona. Po zainstalowaniu w środowisku wirtualnym Pythona, Maturin może być użyty z linii poleceń do inicjalizacji nowego projektu Rust z włączonymi wiązaniami Pythona. Deweloper używa dyrektyw w kodzie Rust, aby wskazać, jakie funkcje Rust mawyeksponować do Pythona, i jak wyeksponować cały projekt Rust do Pythona jako moduł importowalny.

Mapowanie typów Rusta i Pythona

Jednym z przydatnych aspektów PyO3 jest mapowanie pomiędzy typami Rust i Python. Funkcje napisane w Rust mogą akceptować zarówno natywne typy Pythona, jak i typy Rust konwertowane z typów Pythona. Na przykład bytearray lub obiekt bytes w Pythonie może elegancko odwzorować się na Vec<u8> w Rust, a str w Pythonie może być renderowany jako String w Rust.

Konwersja z Pythona na Rusta wiąże się z kosztem per-call, ale uwalnia od konieczności całkowitego użycia typów Pythona w kodzie Rust. W świecie Cython jest to podobne do konwersji na typy C: istnieje koszt każdej konwersji, ale przynoszą one znaczne przyspieszenie, jeśli twoim celem jest przetwarzanie numeryczne całkowicie w C.

Wywoływanie Pythona z Rusta za pomocą skrzynki cpython

Jeśli jesteś głównie programistą Rust, ale chcesz używać Pythona w aplikacji Rust, skrzynka cpython jest prostym sposobem, aby to zrobić. Skrzynka cpython dostarcza wiązania Rust do interpretatora CPython, który jest najbardziej powszechnym runtime Pythona (nazwanym tak, ponieważ jest napisany w C).

Programy Rust mogą wywoływać interpretator CPython i pracować z nim, umożliwiając tworzenie i manipulowanie obiektami Pythona w Rust oraz wykonywanie wywołań bibliotek. Jeden przykład w dokumentacji pokazuje, jak zainicjować runtime Pythona, zaimportować moduły, stworzyć obiekty Pythona i wykonać wywołania metod.

Skrzynka cpython zawiera również kilka przydatnych makr. Na przykład makro py_fn! opakowuje funkcję Rusta tak, aby można ją było wywołać z Pythona. Makro py_class! umożliwia generowanie klas Rust jako obiektów klas Pythona.

Wskazówka dotycząca wydajności

Ważnym zastrzeżeniem zarówno w przypadku cpythona, jak i PyO3 jest to, aby zawsze minimalizować liczbę razy, kiedy dane są przekazywane tam i z powrotem pomiędzy dwoma językami. Każde wywołanie z Pythona do Rusta lub odwrotnie powoduje pewien narzut. Jeśli narzut przewyższa pracę, którą wykonujesz w Rust, nie zobaczysz żadnej znaczącej poprawy wydajności.

Na przykład, jeśli zapętlamy się nad kolekcją obiektów, wyślijmy obiekt do Rust i wykonajmy tam pętlę. Jest to bardziej wydajne niż pętla po stronie Pythona i wywoływanie kodu Rust z każdą iteracją pętli.

Ta wytyczna ma również ogólne zastosowanie do integracji między Pythonem a innym kodem, który używa C ABI Pythona, takim jak moduły Cython.

Źródło: InfoWorld

W celu komercyjnej reprodukcji treści Computerworld należy zakupić licencję. Skontaktuj się z naszym partnerem, YGS Group, pod adresem [email protected]

TOP 200