Python è di per se un linguaggio a tipizzazione debole, dove i tipi non vengono controllati a tempo di esecuzione. Si può “riportare” in Python un po’ della funzionalità dei linguaggi a tipizzazione forte usando i cosiddetti type hints.
Questi di specificare i tipi attesi delle variabili, dei parametri delle funzioni e dei valori di ritorno. I type hints non influenzano il comportamento a runtime, ma consentono:
- Migliore documentazione del codice;
- Supporto migliorato dagli IDE (auto-completamento, rilevamento degli errori);
- Controllo statico dei tipi con strumenti come mypy;
- Migliore manutenibilità del codice.
Tipi base
Per i tipi base (vedere Variabili in Python), possiamo usare direttamente i nomi dei tipi:
int: tipi interi;float: tipi a virgola mobile;bool: tipi booleani;str: tipi stringa;bytes: sequenze di byte;None: il tipo nullo.
Tipi derivati
Per i tipi derivati (come le Collezioni), a partire da Python 3.10, si può usare la seguente sintassi:
numbers: list[int] # numbers è una lista di tipi interi
coordinates: tuple[float, float] # coordinates è una tupla (float, float)
# ...Prima di Python 3.10, si doveva usare il modulo typing:
from typing import List, Dict, Tuple, Set
numbers: List[int] = [1, 2, 3, 4, 5]
coordinates: Tuple[float, float] = (10.5, 20.3)dove i tipi derivati venivano ridefiniti come classi (quindi stavolta con la lettera maiuscola, per distinguere). Per questi tipi ridefiniti valevano i type hint coi tipi base.
Funzioni con type hint
I type hint, base o derivati, possono usarsi anche nelle funzioni:
def divide(a: int, b: int) -> float:
return a / bdove la sintassi a freccia -> indica il tipo di ritorno.
Tipi callable
Esiste un tipo particolare di tipo derivato definito in typing, che è il tipo callable, usato per funzioni (o funzioni lambda, sostanzialmente oggetti che possono essere chiamati come funzioni):
OperationFunc = Callable[[int, int], float]
def apply_operation(x: int, y: int, operation: OperationFunc) -> float:
return operation(x, y)
def divide(a: int, b: int) -> float:
return a / b# Usage
result = apply_operation(10, 5, divide) # restituisce 2.0Tipi unione
I tipi unione sono type hint su più possibili tipi. Questi, ad oggi, stanno nel modulo typing. Si specificano con la sintassi a | (da Python 3.12) o come Union:
from typing import Union
value: Union[int, str] = 42
value: int | str = 42Alias di tipo
Python permette di definire alias di tipo (sostanzialmente definizioni di tipo), secondo 2 modalità (una moderna, a partire da Python 3.12, e una legacy basata su typing, che sfrutta il tipo TypeAlias
# da 3.12
Url = str
def retry(url: Url, retry_count: int) -> None
# prima
from typing import TypeAlias
Url: TypeAlias = str
def retry(url: Url, retry_count: int) -> None:Generic
Infine, notiamo che il Python moderno supporta i generic come molti altri linguaggi:
from typing import TypeVar, Generic, List
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self) -> None:
self.items: List[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
int_stack = Stack[int]() # stack di interi
str_stack = Stack[str]() # stack di stringhe