Dla języka programowania Python – rok 2020 należał zdecydowanie do udanych. Po pierwsze – w rankingu popularności języków programowania (opublikowanym w styczniu 2020) przeprowadzonym przez RedMonk (firma analityczna) znalazł się na II-gim miejscu, wyprzedzając tym samym Javę, która zajęła III-e miejsce. Po drugie, Python doczekał się nowej wersji 3.9. Jak wiadomo nowa wersja to nowe funkcjonalności, o których opowie nam Konrad Gawda – Cloud Evangelist i trener programowania.
Diverse CG: Pierwszą zmianą w Pythonie to przede wszystkim sposób, w jaki Python jest rozwijany i wydawany – aktualnie każdy nowy major będzie implementowany co rok, a nie co 18 miesięcy, jak to miało miejsce do tej pory. Jak to wpływa na funkcjonalność?
Konrad Gawda: Pyton 3.9 jest pierwszą wersją wydaną w takim odstępie czasu od wydania wersji poprzedniej. Dyskusja o takiej zmianie toczyła się na przestrzeni zeszłego roku (wokół propozycji PEP 602, którą złożył Łukasz Langa) i zakończyła się decyzją podjętą w listopadzie.
Chociaż osobiście nie jestem zwolennikiem częstych zmian w językach, to cykl roczny wydaje się dobrym dopasowaniem do szybkiego rozwoju technologii. W końcu Python to nie tylko czysto abstrakcyjna składnia (chociaż i tu jest miejsce na przemyślane zmiany), implementacja (gdzie trzeba stale szlifować wydajność), ale i tzw. "batteries included" - zestaw bibliotek, które nie mogą żyć w oderwaniu od rzeczywistości.
DCG: W nowej wersji zostały wprowadzone dwie zmiany, które mają zwiększyć szybkość technologii. Jaki wpływ na szybkość ma użycie protokołu vectorcall?
KG: Samego interpreter Pythona, CPython, jest oparty na języku C. Również użytkownicy mogą wykorzystywać ten język do tworzenia własnych modułów, szczególnie tam, gdzie potrzebna jest wysoka wydajność obliczeń. Jednocześnie jednak, pojawia się dodatkowe opóźnienie za każdym razem, kiedy trzeba "przetłumaczyć" wywołanie funkcji między dwoma językami.
Na wewnętrzne potrzeby, CPython używał własnych "tricków" na przyśpieszenie tego procesu. Jednak dla programistów piszących niezależne rozszerzenia dostępny był tylko interfejs tp_call - niezbyt wydajny, ale dający pełnię funkcjonalności.
Python 3.9 wprowadza jako dojrzały nowy sposób przekazywania wywołań między językami - wspomniany vectorcall. Nie zastąpi on w stu procentach funkcjonalności udostępnianych przez tp_call , ale powinien wystarczyć w znacznej większości przypadków. A programiści zyskują to, o co walczy się w rozszerzeniach w C - jeszcze większą wydajność.
DCG: Na szybkość tej technologii wpływa również parser dla kodu źródłowego – jaka jest jego rola?
KG: Kod źródłowy programu trzeba w którymś momencie przerobić z sekwencji liter na bardziej abstrakcyjną strukturę (AST – Abstract Syntax Tree). Dotychczas Python używał w tym celu parsera o dosyć prostym sposobie działania, zwanego LL(1). To rozwiązanie pozostaje jeszcze z nami w nowym wydaniu, ale już nie jako domyślne (trzeba użyć np. opcji python -X oldparser) i ma być usunięte w wersji 3.10.
Jego miejsce zajmuje parser PEG (Parsing Expression Grammar). To bardziej złożona maszyneria, jednak autorzy zadbali, żeby nie pogorszyć naszych osiągów. Z opinii dostępnych w sieci wynika, że nowe rozwiązanie działa nieco szybciej, zajmując przy tym odrobinę więcej pamięci. Jednak są to różnice marginalne i nie należy się spodziewać zauważalnego wpływu na aplikacje.
Czemu w takim razie ma służyć zmiana? To otwarcie drzwi do nowych funkcjonalności, które mogą pojawić się w kolejnych wersjach. Przykładem takiego kolejnego kroku jest Structural Pattern Matching, które ma między innymi pozwolić na wygodne rozpakowywanie zmiennej (np. kiedy wywołać a, b = value , a kiedy a, b, c = value).
DCG: Kolejną nową funkcjonalnością są zmiany w dekoratorach. Czy mógłbyś powiedzieć, jakie jest ich znaczenie i jaki mają wpływ na działanie tej technologii?
KG: Dekoratory to jedna z perełek Pythona. Pozwalają one w bardzo krótki i całkiem czytelny sposób zrobić "coś więcej" z funkcjami, które piszemy – zmodyfikować ich wynik, sprawdzić wymagany warunek (np. czy użytkownik jest zalogowany), albo dopisać taką funkcję do spisu (np. jako powiązaną z zapytaniem o konkretny adres URL).
Zmiana wprowadzona w Pythonie 3.9 jest niewielka, ale czasem może ułatwić życie. Otóż, wskazując dekorator nie jesteśmy ograniczeni do podania jego nazwy - możemy użyć bardziej złożonego kodu, jak pobrania ze słownika np. @buttons["hello"].clicked.connect
DCG: Jaka jest rola Type Hints?
KG: Jedną z podstawowych cech Pythona jest dynamiczne typowanie (czyli to, że ta sama zmienna pracownik raz może przechowywać numer kadrowy, a raz imię i nazwisko). To ogromna wygoda, ale i utrudnienie w analizowaniu kodu. W szczególności nowoczesne edytory, w których piszemy programy (IDE) potrafią być bardzo pomocne w podpowiadaniu i wskazywaniu potencjalnych błędów – ale bez dodatkowego źródła wiedzy zmuszone były dedukować (a dokładniej: dokonywać inferencji) typów danych, jakie przyjmuje dana zmienna na podstawie zaobserwowanych przypadków użycia.
W Pythonie 3 mamy dostępne porządne rozwiązanie tego problemu. Type Annotations, zwane też Type Hints, jak nazwa wskazuje, są sposobem przekazania podpowiedzi o typie danych (np. definiując zmienną rok: int = 2020). Jako takie, nie mają one wpływu na samo wykonanie programu i interpreter nie mrugnie okiem, jeśli dokonamy przypisania wbrew zapowiedzi. Natomiast jest to niezastąpione źródło wiedzy dla IDE, czy innych sprytnych analizatorów kodu.
DCG: Nowa funkcjonalność w obszarze Type Hintingu poprawiła jego obsługę, ale jak wpływa to na użyteczność Pythona?
KG: Python 3.9 wprowadza tutaj dwie zmiany. Pierwsza jest czysto praktyczna: aby zadeklarować kolekcję, na przykład listę liczb całkowitych trzeba było zaimportować dodatkową klasę z biblioteki typing. Teraz możemy użyć bezpośrednio danego typu, np.: liczby: list[int].
Druga zmiana związana jest nieco z powrotem do korzeni. Type Hints wykorzystują mechanizm adnotacji wprowadzony w Python 3.0. Z założenia miał on być wykorzystywany do przypisywania zmiennym różnych metadanych, na przykład jednostka miary (np. litry czy galony? każdy kto śledził historię sond wysyłanych na Marsa, wie jak ważne to pytanie). Stało się jednak tak, że Type Hints zdobyły popularność i nie było sposobu stosowania ich jednocześnie razem z innymi adnotacjami. Python 3.9 daje właśnie taki sposób :)
DCG: Co jeszcze zmieniło się w Pythonie?
KG: Rzeczą bardzo istotną, są "unie" (unions) słowników. Pomysł wydaje się być tak oczywisty, że aż dziwi, dlaczego wcześniej używając Pythona nie narzekaliśmy na ich brak. Chodzi o możliwość łączenia zawartości słowników, za pomocą pionowej kreski (pipe) – czyli takiej samej składni, jaka dostępna jest dla zbiorów. Dla przykładu: {0: ‘zero’} | {1: ‘jeden’}.
To może też dobry moment, żeby wspomnieć o zmianach z poprzednich wersji. W pamięć oczywiście zapadają najbardziej kontrowersyjne wybory, dotykające podstaw, które wcześniej wydawały się niezmienne. Dla mnie będzie to operator := znany jako walrus (mors) z wydania 3.8 i zapamiętywanie kolejności elementów przez słowniki (wersja 3.7). Z kolei od Python 3.6 zaszła przełomowa zmiana: mamy do dyspozycji "f-string" - nową metodę budowania ciągów tekstowych. Dla mnie wprowadza ona gwałtowną zmianę w filozofii patrzenia na kod – ale, trzeba przyznać, za tę cenę dostajemy ogromnie wygodne narzędzie.
___________________________________
Konrad Gawda zajmuje się popularyzacją rozwiązań chmurowych dla Orange Polska, jest też trenerem programowania w języku Python. Ukończył Politechnikę Warszawską w 2010 r., karierę rozpoczął jako specjalista R&D w Orange Labs. Zaangażowany w warszawskie spotkania użytkowników Pythona od pierwszego spotkania w 2011 r. Pracował na przecięciu tematów oprogramowania i sieci, przy wdrożeniach Software Defined Networking i chmury sieciowej NFVI.