Adnotacje, które opisują, a nie wymuszają
Type hint (adnotacja typu) to notatka dołączona do nazwy, zwykle parametru funkcji, która mówi "to powinien być int", "to zwraca listę napisów" i tak dalej. Python nie sprawdza ich w trakcie działania. Przekazanie napisu tam, gdzie adnotacja mówi int, nie zgłasza błędu. Twój edytor i zewnętrzne narzędzia (mypy, pyright, Pylance w VS Code oparty na Pyright) czytają adnotacje i ostrzegają cię, zanim kod zostanie uruchomiony.
Najprostszy możliwy przypadek:
name: str to adnotacja parametru. -> str to adnotacja wartości zwracanej. Oba wywołania działają. Drugie jest błędne (statyczne sprawdzanie typów by je oznaczyło), ale sam Python spokojnie je wykonuje, bo 42 akurat obsługuje wstawianie przez f"{...}".
To kluczowy model myślowy: adnotacje to dokumentacja, którą potrafi przeczytać maszyna. Nie zmieniają działania programu.
Po co się tym zajmować?
Trzy konkretne korzyści, w kolejności, w jakiej się zwracają:
- Twój edytor staje się mądrzejszy. Autouzupełnianie pokazuje właściwe metody, zmiany nazw rozchodzą się poprawnie, a najechanie na zmienną pokazuje jej typ.
- Sygnatury funkcji same się opisują.
def fetch(url: str, timeout: float = 5.0) -> dict:mówi czytelnikowi dokładnie, co przekazać i co dostanie z powrotem, bez czytania ciała funkcji. - Narzędzia do sprawdzania typów wyłapują błędy przed uruchomieniem kodu. Uruchomienie
mypy .na projekcie ujawnia błędy, które testy jednostkowe często przegapiają:Nonezwrócone tam, gdzie oczekiwano wartości, słownik użyty w miejscu listy.
W jednoplikowym skrypcie tylko dla ciebie i tylko na dziś pomiń adnotacje. We wszystkim, do czego wrócisz albo czym się podzielisz, piętnaście sekund potrzebnych na ich napisanie zwraca się w ciągu godziny.
Podstawowe typy wbudowane
Żaden z nich nie wymaga importu:
Adnotacje zmiennych (name: str = "Rosa") rzadko są potrzebne, bo Python wnioskuje typ z prawej strony przypisania. Zostaw je dla parametrów, typów zwracanych i sporadycznych przypadków, gdy wywnioskowany typ jest niejednoznaczny.
Funkcje, które nic nie zwracają, używają -> None:
Listy, słowniki, krotki i zbiory
Kontenery wymagają drugiej informacji: co zawierają. Współczesny Python pozwala indeksować wbudowane typy bezpośrednio:
Czytając je na głos:
list[float]: lista liczb float.dict[str, int]: słownik z kluczami typu str i wartościami typu int.tuple[float, float]: krotka z dokładnie dwiema liczbami float.set[str]: zbiór napisów.
Składnia z nawiasami list[...], dict[...] działa w Pythonie 3.9 i nowszych. W starszym kodzie zobaczysz List, Dict, Tuple importowane z typing: to samo znaczenie, starszy zapis.
Wartości opcjonalne
"Może być None" to częsty przypadek. Ma dwa równoważne zapisy, oba są w porządku, ale nowszy czyta się lepiej:
str | None znaczy "napis albo None". Składnia z | działa w Pythonie 3.10+. W starszym kodzie zobaczysz Optional[str] z modułu typing, co znaczy to samo.
Osoba wywołująca funkcję, która widzi -> str | None, wie, że przed użyciem wyniku trzeba sprawdzić None. Na tym polega cały sens tej adnotacji.
Typy Union: to albo tamto
Gdy wartość może być jednym z kilku typów, użyj |:
Możesz połączyć więcej niż dwa typy. int | str | float znaczy "dowolny z tych trzech".
Adnotacje zmiennych w funkcjach
Zwykle Python potrafi ustalić typ zmiennej lokalnej na podstawie wartości początkowej. Adnotacja jest potrzebna tylko w takich sytuacjach:
- Kontener startuje pusty i narzędzie do sprawdzania typów nie zgadnie jego zawartości.
- Wartość może mieć kilka typów, a chcesz zdecydować się na jeden.
- Chcesz udokumentować zamiar dla człowieka czytającego kod.
typing.Any to furtka awaryjna: "nie chcę opisywać tego dokładnie". Używaj jej oszczędnie. Nadużywanie Any sprawia, że reszta adnotacji traci wartość.
Adnotacje w klasach
Atrybuty klas i sygnatury metod adnotuje się tak samo jak każdą inną funkcję:
Dataclasses wręcz wymagają adnotacji typów: dekorator @dataclass czyta je, żeby wygenerować __init__ i __repr__. To jedyne miejsce, w którym adnotacje wpływają na działanie programu.
Krotki i przypadek "dowolnej długości"
tuple[...] ma dwie formy, które mylą początkujących:
tuple[float, float]: dokładnie dwie liczby float.tuple[int, ...]: dowolna liczba liczb int....(prawdziwy element składni w systemie typów) znaczy "i tak dalej".
Callable i aliasy typów
Gdy funkcja przyjmuje albo zwraca inną funkcję, użyj Callable:
Callable[[int], int] znaczy "funkcja, która przyjmuje jeden int i zwraca int".
Gdy adnotacja zaczyna się powtarzać, nadaj jej nazwę:
Alias to zwykłe przypisanie w Pythonie. Wszędzie tam, gdzie pasuje długa forma, zadziała krótka nazwa.
Uruchamianie sprawdzania typów
Interpreter Pythona ignoruje adnotacje typów. Żeby je faktycznie sprawdzić, zainstaluj narzędzie do sprawdzania typów. mypy jest oryginałem; pyright (używany przez Pylance w VS Code) jest szybszy.
pip install mypy
mypy your_project/
Pierwsze uruchomienie ujawni błędy w zaskakujących miejscach. Przerabiaj je stopniowo: # type: ignore wycisza pojedynczą linię, gdy musisz iść dalej.
Nowoczesne IDE sprawdzają typy na bieżąco podczas edycji, więc większość informacji zwrotnych dostajesz, zanim zapiszesz plik.
Kiedy type hints nie pasują
- Szybkie skrypty eksploracyjne. Adnotacje utrudniają pracę nad kodem, który żyje godzinę.
- Bardzo dynamiczny kod. Metaprogramowanie, systemy wtyczek i podobne wzorce często wykraczają poza to, co system typów potrafi opisać. Dodaj adnotacje do zewnętrznego API, a wnętrze zostaw luźne.
- Zewnętrzne biblioteki bez typów. Jeśli importowana biblioteka nie ma informacji o typach, do twojego kodu przecieka
Any. Trudno: to nie twój kod do adnotowania.
We wszystkich pozostałych przypadkach type hints to mały nawyk z dużym zyskiem. Kosztuje kilka dodatkowych naciśnięć klawiszy na sygnaturę funkcji. W zamian dostajesz mniej błędów, łatwiejszą refaktoryzację i kod, który sam się dokumentuje.
Dalej: moduły i importy
Masz już wszystkie narzędzia na poziomie funkcji: argumenty, dekoratory, adnotacje typów. Teraz zobaczymy, jak Python organizuje kod w wielu plikach: moduły, pakiety i system importów.
Najczęściej zadawane pytania
Czym są type hints w Pythonie?
Type hints to adnotacje opisujące oczekiwane typy zmiennych, parametrów funkcji i wartości zwracanych. Sam Python nie wymusza ich w trakcie działania: są dla narzędzi (IDE, linterów, narzędzi do sprawdzania typów takich jak mypy czy pyright) i dla ludzi czytających kod.
Czy type hints przyspieszają działanie Pythona?
Nie. Interpreter Pythona ignoruje adnotacje typów w trakcie działania. Przyspieszenie dotyczy twojej pracy nad kodem: edytor wyłapuje więcej literówek, sygnatury funkcji są jaśniejsze, a refaktoryzacja bezpieczniejsza.
Kiedy dodawać type hints?
Dodawaj je do publicznych sygnatur funkcji: parametrów i typów zwracanych. W ciałach funkcji dodawaj je oszczędnie, tylko tam, gdzie typ zmiennej nie jest oczywisty. W jednorazowych skryptach są opcjonalne. We wspólnym kodzie i bibliotekach szybko się zwracają.