Slide dall'Università sulla Programmazione Orientata agli Oggetti in Python: Ereditarietà. Il Pdf esplora l'ereditarietà singola e multipla in Python, con esempi di codice commentato, ed è utile per lo studio autonomo di Informatica a livello universitario.
Mostra di più14 pagine


Visualizza gratis il Pdf completo
Registrati per accedere all’intero documento e trasformarlo con l’AI.
parent + vd child : ())) : your (insertance)
Programmazione Orientata agli Oggetti in Python: Ereditarietà child classes child ab astt) : (crinast (classes)
@ BarchPythomEsempio di ereditarietà con Python Immaginiamo di aver definito una classe Parallelogrammi, che descrive tutti i quadrilateri che hanno i lati opposti uguali a due a due. Questa classe ha come attributi le lunghezze di due lati adiacenti, lato1 e lato2, e come metodo il calcolo della lunghezza del perimetro, che per qualsiasi parallelogramma vale 2*(lato1+lato2). I rettangoli sono un caso particolare all'interno della classe Parallelogrammi: sono infatti i parallelogrammi che hanno tutti gli angoli interni uguali a 90°. Se si vuole definire una classe Rettangoli, perciò, non occorre ripartire da zero. Conviene invece crearla a partire dalla classe Parallelogrammi, facendole ereditare le proprietà di quella classe. Si dice allora che Parallelogrammi è la classe base, o superclasse, mentre Rettangoli è una classe derivata, o sottoclasse. Grazie all'ereditarietà, la classe derivata potrà riutilizzare i membri della classe base.
class Parallelogrammi: # classe base def_init_(self, 11, 12, ar): self.lato1 = l1 self.lato2 = l2 self.angoli_retti = ar def perimetro(self): return (self.lato1 + self.lato2) * 2 def descrizione(self): if self.angoli_retti == False: print('il quadrilatero è un parallelogramma') else: print('il quadrilatero è un rettangolo') class Rettangoli(Parallelogrammi): # sottoclasse def_init_(self, 11, 12, ar): # membri ereditati Parallelogrammi ._ init_(self, 11, 12, ar) def area(self): # metodo specifico return self.lato1 * self.lato2 print('creo un oggetto della sottoclasse:') ret = Rettangoli(7.4, 10, True) ret.descrizione() print('i lati misurano', ret.lato1, 'e', ret.lato2) print('il perimetro misura', ret.perimetro()) print("l'area misura", ret.area())
Definizione: Si ha overriding quando un metodo della classe base viene ridefinito in una sottoclasse con la stessa intestazione ma un comportamento diverso. Nel nostro esempio, la sottoclasse Rombi ridefinisce il metodo perimetro(), perché nel rombo il perimetro si calcola come 4 * lato1 (visto che tutti i lati sono uguali), mentre nella classe base si usava la formula generale per i parallelogrammi.
class Parallelogrammi: # classe base def_init_(self, 11, 12, lug): self.lato1 = l1 self.lato2 = l2 self.lati_uguali = lug def perimetro(self): return (self.lato1 + self.lato2) * 2 def descrizione(self): if self.lati_uguali == True: print("il quadrilatero è un rombo") else: print("è un generico parallelogramma") class Rombi(Parallelogrammi): # sottoclasse def_init_(self, 11, 12=1, lug=True): # valori di default Parallelogrammi ._ init_(self, 11, 12, lug) def perimetro(self): # overriding del metodo return self.lato1 * 4 # Programma principale lato_r = float(input('inserisci il lato del rombo: ')) print("creo un oggetto della sottoclasse:") rom = Rombi(lato_r) rom.descrizione() print('il perimetro misura:', rom.perimetro())
inserisci il lato del rombo: 5.32 creo un oggetto della sottoclasse: il quadrilatero è un rombo il perimetro misura: 21.28
In Python, si usa la parola chiave pass quando si vuole creare una sottoclasse ma non si ha ancora bisogno di aggiungere nulla di nuovo rispetto alla superclasse. Esempio: class Parallelogrammi: def_init_(self, 11, 12): self.lato1 = l1 self.lato2 = l2 def perimetro(self): return (self.lato1 + self.lato2) * 2 class Rettangoli(Parallelogrammi): pass # eredita tutto senza aggiunte # Uso r = Rettangoli(4, 6) print("perimetro:", r.perimetro()) # Usa il metodo ereditato dalla superclasse Rettangoli eredita tutto da Parallelogrammi, senza ridefinire nulla. Il pass serve a dire "non aggiungo altro, ma la classe esiste".
Ecco un diagramma UML creato apposta per te, che rappresenta le relazioni di ereditarietà tra le tre classi: · Parallelogrammi è la superclasse · Rettangoli e Rombi sono sottoclassi Parallelogrammi classe base o superclasse attributi metodi () A Rettangoli Rombi attributi attributi metodi () classi derivate o sottoclassi metodi ()
Il metodo super() di Python semplifica la gestione dei meccanismi dell'ereditarietà e dell'overriding. Una caratteristica utile di super() è che consente di riferirsi alla superclasse senza nominarla esplicitamente, evitando ridondanze. Ad esempio, al posto di: Parallelogrammi ._ init_(self, 11, 12, lug) si può scrivere: super() ._ init_(11, 12, lug) Inoltre, si usa super() anche per ridefinire i metodi (overriding) e mantenere l'accesso ai metodi originali della superclasse.
class Rettangoli: def _init_(self, b, a): self.base = b self.altezza = a def area(self): return self.base * self.altezza def perimetro(self): return (self.base + self.altezza) * 2 class Quadrati(Rettangoli): def _init_(self, I): # solo un argomento super() ._ init_(I, I) lato_q = float(input("inserisci il lato del quadrato: ")) print("creo un oggetto della sottoclasse:") quad = Quadrati(lato_q) print("l'area misura", quad.area()) print("il perimetro misura", quad.perimetro()) Grazie a super(), la sottoclasse Quadrati può utilizzare i metodi della superclasse passando un solo parametro, che viene duplicato per simulare base e altezza.
Testo trascritto: Si possono anche presentare situazioni in cui i membri necessari per una sottoclasse non sono derivabili da un'unica superclasse. Per questi casi il linguaggio Python permette di introdurre un'ereditarietà multipla, ossia di far derivare una sottoclasse da più superclassi. In questo modo, una sottoclasse può combinare funzionalità provenienti da diverse classi base. Tuttavia, è importante gestire con attenzione i possibili conflitti tra metodi omonimi ereditati da superclassi diverse, per evitare ambiguità: Python risolve questi conflitti seguendo un ordine chiamato MRO (Method Resolution Order), che stabilisce la gerarchia di ricerca dei metodi.
L'ereditarietà multipla permette a una classe di ereditare attributi e metodi da più di una classe base. Questo può essere utile quando una classe deve combinare funzionalità provenienti da diverse sorgenti. Esempio: class Volante: def_init_(self, sa_volare=True): self.sa_volare = sa_volare def descrivi_volo(self): return "Può volare" if self.sa_volare else "Non può volare" class Nuotatore: def_init_(self, sa_nuotare=True): self.sa_nuotare = sa_nuotare def descrivi_nuoto(self): return "Può nuotare" if self.sa_nuotare else "Non può nuotare" class Pinguino(Volante, Nuotatore): def _init_(self): Volante ._ init_(self, sa_volare=False) Nuotatore ._ init_(self, sa_nuotare=True) def descrivi(self): volo = self.descrivi_volo() nuoto = self.descrivi_nuoto() return f"Pinguino: {volo}, {nuoto}" # Utilizzo pingu = Pinguino() print(pingu.descrivi()) Output: Pinguino: Non può volare, Può nuotare In questo esempio, la classe Pinguino eredita sia da Volante che da Nuotatore. Questo le consente di combinare comportamenti da entrambe le classi base, specificando che i pinguini non possono volare ma possono nuotare.
class MezzoDiTrasporto: def_init_(self, velocita_media, consumo_km=0.0, carburante="Nessuno", infrastruttura=False): self.velocita_media = velocita_media self.consumo_km = consumo_km self.carburante = carburante self.infrastruttura = infrastruttura def calcola_durata(self, distanza): return distanza / self.velocita_media def calcola_consumo(self, distanza): return distanza * self.consumo_km Questa è la classe base che definisce le proprietà e i metodi comuni a tutti i mezzi di trasporto. Include attributi come velocità media, consumo per chilometro, tipo di carburante e necessità di infrastruttura. I metodi permettono di calcolare la durata di un viaggio e il consumo di carburante.
class VeicoloAMotore(MezzoDiTrasporto): def_init_(self, velocita_media, consumo_km, carburante, cilindrata, numero_cilindri): # Inizializza gli attributi della classe madre super() ._ init_(velocita_media, consumo_km, carburante, infrastruttura=True) # Ora inizializza gli attributi specifici self.cilindrata = cilindrata self.numero_cilindri = numero_cilindri self.giri_motore = 0 def avvia(self): print("Motore avviato.") def spegni(self): print("Motore spento.") def aumenta_giri(self, valore): self.giri_motore += valore print(f"Giri motore: {self.giri_motore}") Questa sottoclasse estende MezzoDiTrasporto aggiungendo caratteristiche specifiche dei veicoli a motore. Oltre agli attributi ereditati, include cilindrata, numero di cilindri e giri del motore. Aggiunge anche metodi per avviare, spegnere e aumentare i giri del motore.