Menu
Coddy logo textTech

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.

Di Kevin Spektor, Cofondatore e CTO

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

TipoChiamato ancheCom'è fattoQuando viene scelta la versione
Per sottotipoPolimorfismo a runtime, override dei metodiUna sottoclasse sostituisce un metodo del genitoreMentre il programma è in esecuzione
Ad hocOverloadingUn nome, più versioni per tipi di parametri diversi; anche l'overloading degli operatoriIn fase di compilazione in Java e C++
ParametricoGenerics, templateUn 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?
L'operatore + 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à?
L'ereditarietà permette a una classe di riutilizzare il codice di una classe genitore. Il polimorfismo permette al codice di trattare tipi diversi attraverso un'unica interfaccia comune. L'ereditarietà è un modo comune per ottenere il polimorfismo, perché una sottoclasse può ridefinire un metodo del genitore, ma il duck typing di Python e le interfacce di Java danno il polimorfismo senza condividere alcun codice.
Cos'è il polimorfismo in biologia?
In biologia, polimorfismo significa che in una stessa popolazione esistono due o più forme di un carattere o di un gene, come i gruppi sanguigni A, B, AB e 0 negli esseri umani. Condivide con il termine della programmazione la radice greca, "molte forme", ma i due concetti non hanno legami tra loro.
Python supporta l'overloading dei metodi?
Non in base al tipo o al numero dei parametri, come fanno Java e C++. Un secondo 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?
Ti permette di aggiungere nuovi tipi senza modificare il codice che li usa. Un programma di disegno che chiama 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.
Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA