Historia pytania
Adnotacje funkcji pojawiły się w Pythonie 3.0, a mechanizm type hints (podpowiedzi typów) opisany jest w PEP 484, dodany z wersją 3.5. Narzędzie zostało stworzone do statycznej analizy kodu, autouzupełniania i zwiększania czytelności — standardowa biblioteka typów (typing) pozwala na jawne wskazywanie oczekiwanych typów zmiennych, argumentów oraz wartości zwracanych przez funkcje.
Problem
Python to język dynamiczny, w którym typy zmiennych mogą zmieniać się w trakcie wykonywania, co może prowadzić do błędów pojawiających się tylko w trakcie działania programu. Adnotacje nie wpływają na wykonywanie kodu, ale przy niewłaściwym ich użyciu programiści mogą mieć błędne poczucie "ścisłej typizacji".
Rozwiązanie
Adnotacje typów stosuje się w dokumentacji, automatycznym sprawdzaniu za pomocą mypy, pylance, pyright i podobnych narzędzi, a także do integracji z IDE. Realizowane są przez dwukropek po nazwie argumentu oraz strzałkę po liście parametrów:**
def greet(name: str, times: int = 1) -> None: for _ in range(times): print(f"Hello, {name}!") # Poprawna adnotacja dla funkcji przetwarzającej słownik from typing import Dict, List def transform(data: Dict[str, List[int]]) -> float: return sum(sum(lst) for lst in data.values()) / 10
Kluczowe cechy:
Czy Python może "automatycznie" sprawdzać zgodność z typami zadeklarowanymi w adnotacjach?
Nie! Sprawdzanie typów odbywa się tylko za pomocą zewnętrznych narzędzi do analizy statycznej, np. mypy. W czasie wykonywania Python całkowicie ignoruje zawartość adnotacji.
def f(x: int): return x * 2 print(f('oops')) # Typ str, błędu nie będzie!
Gdzie przechowywane są adnotacje i jak można je uzyskać w czasie wykonywania, po co to może być potrzebne?
Przechowywane są w specjalnym atrybucie annotations:
def add(x: int, y: int) -> int: return x + y print(add.__annotations__) # {'x': <class 'int'>, 'y': <class 'int'>, 'return': <class 'int'>}
To wykorzystują zewnętrzne biblioteki do walidacji danych, autogeneracji dokumentacji, serializacji itp.
Czy można adnotować dowolną zmienną, tylko funkcje, co będzie w zakresie globalnym?
Można adnotować zarówno lokalne, jak i globalne zmienne przez dwukropek, to także nie wpływa na wykonanie:
index: int = 0 def func(x: 'User') -> None: ...
W projekcie korporacyjnym wszyscy programiści zaczęli aktywnie wdrażać adnotacje, a rzeczywiste typy argumentów funkcji często nie zgadzały się z podanymi. Python przepuszczał te błędy, a nieoczekiwane błędy pojawiały się tylko w głębi logiki biznesowej. Brakowało konfiguracji mypy.
Zalety:
Wady:
Wykorzystanie type hints i obowiązkowe uruchamianie mypy w CI, a także autogeneracja dokumentacji przez annotations:
Zalety:
Wady: