Ereditarietà In Python
Ereditarietà in Python¶
Obiettivi della Lezione¶
Al termine di questa lezione sarai in grado di:
- Comprendere il concetto di ereditarietà nella programmazione orientata agli oggetti.
- Definire classi derivate che ereditano attributi e metodi da classi base.
- Sovrascrivere metodi delle classi base nelle classi derivate.
- Utilizzare la funzione
super()
per accedere ai metodi e agli attributi della classe base. - Implementare l’ereditarietà multipla in Python.
Introduzione¶
L’ereditarietà è uno dei pilastri fondamentali della Programmazione Orientata agli Oggetti (OOP). Consente di creare nuove classi che derivano da classi esistenti, ereditando attributi e metodi, e permettendo così di estendere o modificare il comportamento senza riscrivere tutto da zero. Questo concetto favorisce il riutilizzo del codice e rende il software più organizzato e facile da mantenere.
Spiegazione Teorica¶
Cos’è l’Ereditarietà?¶
L’ereditarietà è un meccanismo che permette ad una classe (denominata classe derivata o sottoclasse) di ereditare attributi e metodi da un’altra classe (denominata classe base o superclasse).
Sintassi Base:
class ClasseDerivata(ClasseBase):
# Corpo della classe derivata
Vantaggi dell’Ereditarietà¶
- Riutilizzo del Codice: Evita la duplicazione del codice comune tra classi.
- Organizzazione Gerarchica: Permette di strutturare le classi in una gerarchia logica.
- Estensibilità: Facilita l’estensione delle funzionalità delle classi esistenti.
Sovrascrittura di Metodi¶
Le classi derivate possono sovrascrivere i metodi della classe base per modificarne il comportamento.
class ClasseDerivata(ClasseBase):
def metodo(self):
# Nuova implementazione del metodo
La Funzione super()
¶
La funzione super()
è utilizzata per accedere ai metodi e agli attributi della classe base all’interno della classe derivata.
class ClasseDerivata(ClasseBase):
def __init__(self):
super().__init__()
# Codice aggiuntivo
Ereditarietà Multipla¶
Python supporta l’ereditarietà multipla, permettendo ad una classe di ereditare da più classi base.
class ClasseDerivata(ClasseBase1, ClasseBase2):
# Corpo della classe derivata
class Animale:
def __init__(self, nome):
self.nome = nome
def saluta(self):
print(f"Ciao, mi chiamo {self.nome}.")
Classe Derivata:
class Cane(Animale):
def abbaia(self):
print("Bau bau!")
Utilizzo:
fido = Cane("Fido")
fido.saluta() # Output: Ciao, mi chiamo Fido.
fido.abbaia() # Output: Bau bau!
Ciao, mi chiamo Fido. Bau bau!
Spiegazione:
- La classe
Cane
eredita daAnimale
. Cane
ha accesso all’attributonome
e al metodosaluta()
diAnimale
.Cane
aggiunge un nuovo metodoabbaia()
.
Esempio 2: Sovrascrittura di Metodi¶
Classe Derivata con Sovrascrittura:
class Gatto(Animale):
def saluta(self):
print(f"Miao, sono il gatto {self.nome}.")
Utilizzo:
felix = Gatto("Felix")
felix.saluta() # Output: Miao, sono il gatto Felix.
Miao, sono il gatto Felix.
Spiegazione:
Gatto
sovrascrive il metodosaluta()
diAnimale
.- Quando si chiama
saluta()
su un’istanza diGatto
, viene eseguito il metodo sovrascritto.
Esempio 3: Utilizzo di super()
¶
Classe Derivata che Chiama la Classe Base:
class Cavallo(Animale):
def __init__(self, nome, razza):
super().__init__(nome)
self.razza = razza
def saluta(self):
super().saluta()
print(f"Sono un cavallo di razza {self.razza}.")
Utilizzo:
spirit = Cavallo("Spirit", "Mustang")
spirit.saluta()
# Output:
# Ciao, mi chiamo Spirit.
# Sono un cavallo di razza Mustang.
Ciao, mi chiamo Spirit. Sono un cavallo di razza Mustang.
Spiegazione:
Cavallo
estende il metodo__init__()
aggiungendo l’attributorazza
.- Utilizza
super().__init__(nome)
per inizializzare l’attributonome
della classe base. - Nel metodo
saluta()
, chiamasuper().saluta()
per eseguire il metodo della classe base e aggiunge ulteriori informazioni.
Esempio 4: Ereditarietà Multipla¶
Classi Base:
class Volante:
def vola(self):
print("Sto volando!")
class Nuotante:
def nuota(self):
print("Sto nuotando!")
Classe Derivata con Ereditarietà Multipla:
class Anatra(Volante, Nuotante):
pass
Utilizzo:
donald = Anatra()
donald.vola() # Output: Sto volando!
donald.nuota() # Output: Sto nuotando!
Sto volando! Sto nuotando!
Spiegazione:
Anatra
eredita da entrambe le classiVolante
eNuotante
.- Ha accesso ai metodi
vola()
enuota()
.
class Veicolo:
def __init__(self, marca, modello):
self.marca = marca
self.modello = modello
def info(self):
print(f"Marca: {self.marca}, Modello: {self.modello}")
class Auto(Veicolo):
def __init__(self, marca, modello, numero_di_ruote):
super().__init__(marca, modello)
self.numero_di_ruote = numero_di_ruote
def info(self):
super().info()
print(f"Numero di ruote: {self.numero_di_ruote}")
# Utilizzo
mia_auto = Auto("Fiat", "500", 4)
mia_auto.info()
# Output:
# Marca: Fiat, Modello: 500
# Numero di ruote: 4
Marca: Fiat, Modello: 500 Numero di ruote: 4
Esercizio 2:¶
Implementa una classe Studente
che eredita da una classe Persona
. La classe Studente
dovrebbe aggiungere l’attributo matricola
e un metodo studia()
che stampa un messaggio indicante che lo studente sta studiando.
Soluzione:
class Persona:
def __init__(self, nome, età):
self.nome = nome
self.età = età
def saluta(self):
print(f"Ciao, mi chiamo {self.nome} e ho {self.età} anni.")
class Studente(Persona):
def __init__(self, nome, età, matricola):
super().__init__(nome, età)
self.matricola = matricola
def studia(self):
print(f"{self.nome} sta studiando.")
# Utilizzo
alice = Studente("Alice", 22, "A12345")
alice.saluta() # Output: Ciao, mi chiamo Alice e ho 22 anni.
alice.studia() # Output: Alice sta studiando.
Ciao, mi chiamo Alice e ho 22 anni. Alice sta studiando.
Buone Pratiche e Consigli¶
- Coerenza nella Gerarchia delle Classi: Utilizza l’ereditarietà solo quando esiste una chiara relazione “è un” tra le classi.
- Evita l’Ereditarietà Multipla Complessa: Può portare a codice difficile da capire e mantenere. Se possibile, preferisci la composizione.
- Utilizza
super()
Correttamente: Quando sovrascrivi metodi, soprattutto__init__()
, utilizzasuper()
per assicurarti che la classe base sia inizializzata correttamente. - Nome Appropriato delle Classi: Assegna nomi significativi alle classi per riflettere le loro responsabilità.
Conclusione¶
L’ereditarietà è un potente strumento della programmazione orientata agli oggetti che consente di creare classi più flessibili e riutilizzabili. Comprendendo come funzionano le classi base e derivate, come sovrascrivere metodi e come utilizzare super()
, sarai in grado di scrivere codice più efficiente e organizzato. Ricorda di utilizzare l’ereditarietà in modo appropriato per mantenere il tuo codice chiaro e facilmente manutenibile.
Risorse Aggiuntive¶
Documentazione Ufficiale Python: Ereditarietà
Libro Consigliato: Python Crash Course di Eric Matthes
- Video Tutorial: Python OOP Tutorial 4: Inheritance – Creating Subclasses