Cos'è il polimorfismo?
In programmazione, il polimorfismo è la capacità di un pezzo di codice, come una chiamata di funzione o il nome di un metodo, di funzionare con valori di tipi diversi, ognuno dei quali fornisce il proprio comportamento. Chiamare shape.area() esegue un calcolo diverso per un cerchio e per un quadrato.
Aggiornato il 24 settembre 2026
In Python, len("hello") restituisce 5, len([4, 8, 15]) restituisce 3 e len({"a": 1}) restituisce 1. È un unico nome di funzione usato su tre tipi, e ogni tipo conta a modo suo: una stringa conta i caratteri, una lista conta gli elementi, un dizionario conta le chiavi. La parola viene dal greco: poly, molti, e morph, forma. Una sola chiamata, molte forme di comportamento.
Come funziona il polimorfismo
Il codice chiama un metodo per nome, come shape.area(). Quando quella riga viene eseguita, il linguaggio guarda l'oggetto reale e trova area nella classe dell'oggetto stesso. Questa ricerca si chiama dispatch dinamico, ed è ciò che permette a una sola riga di fare un lavoro diverso per oggetti diversi:
Circle 3.14
Square 9
Circle 12.57
Python trova il metodo cercando prima nella classe dell'oggetto, poi nelle sue classi genitore in un ordine fisso chiamato method resolution order (ordine di risoluzione dei metodi). Se Square non avesse una propria area(), la ricerca arriverebbe a Shape.area() e solleverebbe NotImplementedError, un segnale che ogni sottoclasse deve fornirne una.
Il ciclo non controlla mai che tipo di forma contiene. Per aggiungere un triangolo, scrivi una classe Triangle con la sua area(), e il ciclo funziona senza modifiche. Senza polimorfismo, il ciclo avrebbe bisogno di un ramo if isinstance(...) per ogni forma, da modificare ogni volta che ne compare una nuova.
Tipi di polimorfismo
| Tipo | Chiamato anche | Com'è fatto | Quando viene scelta la versione |
|---|---|---|---|
| Per sottotipo | Polimorfismo a runtime, override dei metodi | Una sottoclasse sostituisce un metodo del genitore | Mentre il programma è in esecuzione |
| Ad hoc | Overloading | Un nome, più versioni per tipi di parametri diversi; anche l'overloading degli operatori | In fase di compilazione in Java e C++ |
| Parametrico | Generics, template | Un pezzo di codice che funziona per qualsiasi tipo: List<T> in Java, vector<T> in C++ | In fase di compilazione |
Quando nella programmazione a oggetti si dice "polimorfismo" senza altri dettagli, si intende quasi sempre la prima riga: il polimorfismo per sottotipo tramite override.
Python li ha tutti e tre a modo suo. L'override funziona come nell'esempio delle forme. Operatori come + sono polimorfismo ad hoc. Funzioni come max() e sorted() sono parametriche nello spirito: accettano una lista di numeri, stringhe o date, purché gli elementi si possano confrontare, e i type hint come list[int] o un TypeVar possono dichiararlo esplicitamente.
Polimorfismo in fase di compilazione e a runtime in Java
Java li ha entrambi, e nei colloqui di lavoro capita spesso che chiedano la differenza:
class Animal { String sound() { return "..."; } }
class Dog extends Animal {
@Override String sound() { return "Woof"; }
}
Animal pet = new Dog();
pet.sound(); // "Woof": chosen at run time from the object
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
add(2, 3); // int version, chosen by the compiler
add(2.5, 1.0); // double version
La variabile pet è di tipo Animal, eppure viene eseguita la versione di Dog, perché la scelta dipende dall'oggetto, non dalla variabile. I due metodi add sono overloading: il compilatore ne sceglie uno in base ai tipi degli argomenti prima che il programma venga eseguito. Le interfacce danno lo stesso comportamento a runtime senza condividere codice: qualsiasi classe che implementa Comparable può essere ordinata da Collections.sort. C++ funziona allo stesso modo con una differenza: un metodo ha il dispatch a runtime solo se è dichiarato virtual. Vedi il polimorfismo in Java, l'overloading dei metodi e le funzioni virtuali in C++.
Polimorfismo in Python: duck typing e operatori
Python non richiede una classe genitore comune. Se un oggetto ha il metodo che il codice chiama, funziona: "se cammina come un'anatra e fa qua qua come un'anatra, è un'anatra". Anche gli operatori sono polimorfici. Scrivere a + b chiama a.__add__(b), quindi le tue classi possono supportare +, len() e print():
3 abcd [1, 2]
Vector(11, 22)
5 3 2
L'ereditarietà è un modo per ottenere il polimorfismo, non un requisito. Vector non eredita da niente di speciale, eppure len() e + lo trattano come un tipo integrato. La documentazione sull'ereditarietà in Python mostra la strada delle sottoclassi.
Errori comuni
Aspettarsi che Python faccia overloading in base alla firma. Un secondo def con lo stesso nome sostituisce il primo senza avvisare:
Hi Ana Silva
Traceback (most recent call last):
...
TypeError: greet() missing 1 required positional argument: 'last'
Usa invece un argomento predefinito: def greet(first, last="").
Dimenticare virtual in C++. Senza di esso, chiamare un metodo tramite un puntatore alla classe base esegue la versione base, anche quando l'oggetto è una sottoclasse.
Override che cambiano il significato. Se area() in una sottoclasse restituisce il perimetro, ogni chiamante che si fida di area() si rompe. Un override deve mantenere la promessa fatta dal genitore; questa regola è nota come principio di sostituzione di Liskov.
Controlli di tipo ovunque. Una catena di rami if type(x) == ... di solito è il segnale che ogni tipo dovrebbe avere il proprio metodo.
Cosa leggere dopo
Il polimorfismo lavora insieme all'incapsulamento, che protegge i dati di ogni oggetto, e all'astrazione, che definisce l'interfaccia comune implementata dai tipi. Esercitati con l'override nella documentazione sulle classi Python, oppure prova il corso Java, dove overloading e override compaiono fianco a fianco.
Domande frequenti
Qual è un esempio di polimorfismo?
+ in Python: 1 + 2 somma numeri, "ab" + "cd" unisce stringhe e [1] + [2] unisce liste. Lo stesso simbolo funziona su tre tipi, e ogni tipo decide cosa significa. Nel codice a oggetti, l'esempio classico è una lista di forme in cui ognuna risponde ad area() con la propria formula.Qual è la differenza tra polimorfismo ed ereditarietà?
Cos'è il polimorfismo in biologia?
Python supporta l'overloading dei metodi?
def con lo stesso nome sostituisce il primo. Il codice Python ottiene lo stesso effetto con argomenti predefiniti, *args o functools.singledispatch, che sceglie una funzione in base al tipo del primo argomento.A cosa serve il polimorfismo?
shape.draw() su ogni forma non richiede modifiche quando aggiungi una classe triangolo; si scrive solo la nuova classe. Senza polimorfismo, quel ciclo si allungherebbe con un nuovo ramo if per ogni tipo.