Menu

Type hints w Pythonie: adnotacje typów dla funkcji, list, słowników i nie tylko

Czym są adnotacje typów w Pythonie, kiedy pomagają i jaka jest składnia adnotowania zmiennych, sygnatur funkcji, kontenerów i wartości opcjonalnych.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

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ą:

  1. 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.
  2. 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.
  3. 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ą: None zwró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ą.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ