Polimorfismo In Python
Polimorfismo in Python¶
Obiettivi della Lezione¶
Al termine di questa lezione, sarai in grado di:
- Comprendere il concetto di polimorfismo nella programmazione orientata agli oggetti.
- Implementare il polimorfismo in Python attraverso metodi e funzioni.
- Utilizzare il polimorfismo per scrivere codice più flessibile e riutilizzabile.
- Riconoscere l’importanza del polimorfismo nell’ereditarietà e nell’override dei metodi.
Introduzione¶
Il polimorfismo è uno dei pilastri fondamentali della programmazione orientata agli oggetti (OOP), insieme all’incapsulamento e all’ereditarietà. La parola “polimorfismo” deriva dal greco e significa “molte forme”. In informatica, il polimorfismo permette a oggetti di classi diverse di essere trattati come oggetti di una classe comune, specialmente attraverso metodi comuni. Questo consente di scrivere codice più generale e flessibile.
Spiegazione Teorica¶
Cos’è il Polimorfismo?¶
Il polimorfismo permette a un’interfaccia comune di essere utilizzata per tipi di dati diversi. In Python, grazie alla sua natura dinamica, il polimorfismo è intrinseco e consente di utilizzare oggetti diversi in modo intercambiabile se condividono metodi o attributi comuni.
Tipi di Polimorfismo¶
Polimorfismo di Sottotipi (Override dei Metodi):
- Le classi derivate possono sovrascrivere metodi delle classi base.
- Permette di fornire implementazioni specifiche per metodi ereditati.
Polimorfismo Parametrico:
- Funzioni o metodi che possono funzionare con qualsiasi tipo di dato.
- In Python si realizza attraverso funzioni generali che operano su oggetti con metodi o attributi necessari.
Polimorfismo di Ad hoc (Sovraccarico):
- Python non supporta direttamente il sovraccarico dei metodi come altri linguaggi (ad esempio, C++).
- Tuttavia, è possibile simulare questo comportamento mediante argomenti di default o *args e **kwargs.
Perché il Polimorfismo è Importante?¶
- Flessibilità: Consente di scrivere codice che funziona con oggetti di tipi diversi ma con interfacce simili.
- Estensibilità: Permette di aggiungere nuovi tipi di oggetti senza modificare il codice esistente.
- Mantenibilità: Riduce la complessità del codice e facilita la gestione di grandi codebase.
class Cane:
def suono(self):
return "Bau!"
class Gatto:
def suono(self):
return "Miao!"
def fai_suono(animale):
print(animale.suono())
cane = Cane()
gatto = Gatto()
fai_suono(cane) # Output: Bau!
fai_suono(gatto) # Output: Miao!
Bau! Miao!
Spiegazione:
La funzione fai_suono
accetta qualsiasi oggetto che abbia il metodo suono()
. Non importa di che classe sia l’oggetto, purché fornisca l’implementazione del metodo richiesto.
Esempio 2: Polimorfismo con Ereditarietà¶
class Animale:
def suono(self):
pass
class Cane(Animale):
def suono(self):
return "Bau!"
class Gatto(Animale):
def suono(self):
return "Miao!"
animali = [Cane(), Gatto()]
for animale in animali:
print(animale.suono())
Bau! Miao!
Spiegazione:
Le classi Cane
e Gatto
ereditano dalla classe base Animale
e sovrascrivono il metodo suono()
. Il ciclo for itera su una lista di oggetti Animale
e chiama il metodo suono()
, mostrando il comportamento polimorfico.
Esempio 3: Polimorfismo con Funzioni Incorporate¶
print(len("Ciao")) # Output: 4
print(len([1, 2, 3])) # Output: 3
print(len({'a': 1, 'b': 2})) # Output: 2
4 3 2
Spiegazione:
La funzione len()
è polimorfica perché può operare su diversi tipi di dati (stringhe, liste, dizionari) e restituisce un risultato coerente.
import math
class Forma:
def area(self):
pass
class Rettangolo(Forma):
def __init__(self, larghezza, altezza):
self.larghezza = larghezza
self.altezza = altezza
def area(self):
return self.larghezza * self.altezza
class Cerchio(Forma):
def __init__(self, raggio):
self.raggio = raggio
def area(self):
return math.pi * self.raggio ** 2
forme = [Rettangolo(3, 4), Cerchio(5)]
for forma in forme:
print(f"L'area è: {forma.area()}")
L'area è: 12 L'area è: 78.53981633974483
Esercizio 2: Gestione di Veicoli¶
Definisci una classe Veicolo
con un metodo muovi()
. Crea le classi Auto
e Bicicletta
che ereditano da Veicolo
e implementano il metodo muovi()
in modo appropriato.
Buone Pratiche e Consigli¶
- Utilizzare Nomi Coerenti: Assicurati che i metodi che devono essere polimorfici abbiano lo stesso nome nelle diverse classi.
- Evitare Dipendenze Rigide: Scrivi funzioni e metodi che dipendono da interfacce (metodi e attributi) piuttosto che da tipi concreti.
- Favorire la Composizione: Oltre all’ereditarietà, considera l’uso della composizione per creare comportamenti polimorfici.
- Documentare il Codice: Fornisci docstring e commenti che spiegano come e perché il polimorfismo viene utilizzato.
Conclusione¶
Il polimorfismo è un concetto potente che consente di scrivere codice flessibile e riutilizzabile. In Python, grazie alla sua tipizzazione dinamica e all’ereditarietà, implementare il polimorfismo è naturale e intuitivo. Comprendere e utilizzare il polimorfismo ti aiuterà a progettare programmi più organizzati e scalabili.
Risorse Aggiuntive¶
- Documentazione Ufficiale Python: Classes
- Libro Consigliato: Python Crash Course di Eric Matthes
- Video Tutorial: Object Oriented Programming | Polymorphism