EREDITARIETA’

La prima cosa da dire parlando di ereditarietà in Python è che il linguaggio consente ad una classe di ereditare gli attributi e i metodi di un’altra classe. Le sottoclassi o classi derivate che sono le più specializzate ereditano gli attributi e metodi dalle loro classi base o superclassi. Le classi derivate possono ridefinire il comportamento degli attributi ereditati (metodi) mediante override e possono aggiungere delle funzionalità aggiuntive che tendono a specializzare la classe. Le superclassi in genere sono più generiche rispetto alle loro sottoclassi. Quando andiamo a creare un’istanza di una sottoclasse questa risulta essere anche istanza di tutte le superclassi della classe di cui è istanza.

LA FUNZIONE ISINSTANCE

Esiste una funzione isinstance che prende come primo parametro l’istanza e come secondo parametro la classe che si vuol verificare. La funzione restituisce True se ne è istanza False in caso contrario. m1 essendo istanza di AClass è implicitamente istanza anche di BClass, inoltre m1 eredita da BClass sia il costruttore __init_ sia il metodo di istanza printMessage(self) come si può vedere dall’esempio.

Ereditarieta

OVERRIDE

Con l’override possiamo ridefinire gli attributi (metodi) nelle sottoclassi. Nella classe derivata AClass stiamo ridefinendo il comportamento di printMessage(self) anche se in maniera minimale. Quando creiamo un’istanza di AClass che chiamiamo m1 e richiamiamo printMessage(self) di fatto stiamo richiamando il metodo della classe derivata in quanto abbiamo sovrascritto quello della classe base. Il codice che abbiamo scritto tuttavia presenta un problema. Se creiamo un costruttore anche nella classe derivata alla creazione dell’istanza verrà invocato il costruttore della sottoclasse, quello della superclasse verrà ignorato non impostando correttamente l’attributo message. Questo perché  viene eseguito l’override del costruttore della superclasse. Per risolvere questo problema si usa la funzione super().

Override

LA FUNZIONE SUPER()

super() ci consente di accedere ai metodi delle superclassi dalle sottoclassi. La funzione super() fa in modo che venga eseguito il costruttore della superclasse, così passando opportunamente l’attributo message, che riceviamo nel costruttore della sottoclasse, tutti gli attributi verranno inizializzati correttamente.

La funzione super()

PROPERTIES

Normalmente nei linguaggi Object Oriented si tende a incapsulare o rendere privati i dati con dei metodi getter e setter e rendere pubblici i metodi ove necessario. Python non supporta pienamente l’incapsulamento. Si possono creare tramite decoratori getter e setter di una proprietà.

Property Decorator
Property Decorator code
class persona(object):
    def __init__(self,nome,cognome,indirizzo):
        self.__nome_ = nome
        self.__cognome_ = cognome
        self.__indirizzo_ = indirizzo
    @property
    def nome(self):
        return self.__nome_
    @nome.setter
    def nome(self,nome):
        self.__nome_ = nome
    @property
    def cognome(self):
        return self.__cognome_
    @cognome.setter
    def cognome(self,cognome):
        self.__cognome_ = cognome
    @property
    def indirizzo(self):
        return self.__indirizzo_
    @indirizzo.setter
    def indirizzo(self,indirizzo):
        self.__indirizzo_ = indirizzo
    def denominazione(self):
        s= f'Persona Nome: {self.nome} Cognome: {self.cognome} indirizzo: {self.indirizzo}'
        print(s)

class utente(persona):
        def __init__(self,id,numeroconto,saldo,nome,cognome,indirizzo):
            self.__id_ = id
            self.__numeroconto_ = numeroconto
            self.__saldo_ = saldo
            super().__init__(nome,cognome,indirizzo)
        @property
        def id(self):
            return self.__id_
        @id.setter
        def id(self,id):
            self.__id_ = id
        @property
        def numeroconto(self):
            return self.__numeroconto_
        @numeroconto.setter
        def numeroconto(self,numeroconto):
            self.__numeroconto_ = numeroconto
        @property
        def saldo(self):
            return self.__saldo_
        @saldo.setter
        def saldo(self,saldo):
            if (saldo < 0):
                s=f'Impossibile impostare il saldo, valore passato: {saldo}'
                print(s)
                return
            else:
                self.__saldo_ = saldo
        def saldoCorrente(self):
            s = f'Utente: nome {self.nome} cognome {self.cognome} saldo {self.saldo}'
            print(s)

class banca():
        def __init__(self,id,denominazione,abi,cab,utente):
            self.__id_=id
            self.__denominazione_=denominazione
            self.__abi_=abi
            self.__cab_ = cab
            self.__utente_=utente
        @property
        def id(self):
            return self.__id_
        @id.setter
        def id(self,id):
            self.__id_ = id
        @property
        def denominazione(self):
            return self.__denominazione_
        @denominazione.setter
        def denominazione(self,denominazione):
            self.__denominazione_ = denominazione
        @property
        def abi(self):
            return self.__abi_
        @abi.setter
        def abi(self,abi):
            self.__abi_ = abi
        @property
        def cab(self):
            return self.__cab_
        @cab.setter
        def cab(self,cab):
            self.__cab_ = cab
        @property
        def utente(self):
            return self.__utente_
        @utente.setter
        def utente(self,utente):
            self.__utente_ = utente
        def preleva(self,importo,utente):
            if importo < 0 or importo > utente.saldo:
               s = f'Impossibile prelevare, importo passato: {importo} saldo: {utente.saldo}'
               print(s)
               return 
            else:
               utente.saldo -= importo
        def accredita(self,importo,utente):
            if importo < 0:
                s = f'Impossibile accreditare, valore passato: {importo}'
                print(s)
                return 
            else:
                utente.saldo += importo

u1 = utente(12345,"AS67890OL",12000.0,'Mario','Rossi','via delle rose 54')
u2 = utente(678345,"AS67L768",2000.0,'Luigi','Verdi','via della fontana 7')
u1.denominazione()
u2.denominazione()
u1.saldoCorrente()
u2.saldoCorrente()
b1=banca(9873456,'UBI BANCA', 30600,10400,u1)
b2=banca(9876832,'UBI BANCA', 30600,10400,u2)
b1.preleva(5000.0,u1)
u1.saldoCorrente()
b2.accredita(3000.0,u2)
u2.saldoCorrente()

APPROFONDIMENTO

L’ereditarietà è un concetto fondamentale nella programmazione orientata agli oggetti (OOP) in Python. Consente di creare una nuova classe (classe derivata) che eredita attributi e metodi da un’altra classe (classe base o genitore). Questo permette di riutilizzare il codice e di estendere le funzionalità delle classi esistenti.

Concetti chiave

Classe Base (Genitore): La classe da cui vengono ereditati gli attributi e i metodi.

Classe Derivata (Figlio): La classe che eredita dalla classe base.

Sintassi base

Ecco un esempio di come funziona l’ereditarietà in Python:

# Definizione della classe base
class Animale:
        def __init__(self, nome):
           self.nome = nome

        def parla(self):
           return f”{self.nome} fa un suono.”

# Definizione della classe derivata
class Cane(Animale):
        def __init__(self, nome, razza):
           super().__init__(nome)
           self.razza = razza

        def parla(self):
           return f”{self.nome} abbaia.”

# Utilizzo delle classi
mio_cane = Cane(“Fido“, “Labrador“)
print(mio_cane.parla()) # Output: Fido abbaia.

Spiegazione

1. Classe Base (Animale): Definiamo una classe chiamata Animale con un attributo nome e un metodo parla che restituisce una stringa generica.

2. Classe Derivata (Cane): La classe Cane eredita dalla classe Animale. La funzione super() viene utilizzata per richiamare il costruttore della classe base (__init__), permettendo alla classe derivata di inizializzare gli attributi della classe base.

3. Override dei Metodi: Nella classe Cane, il metodo parla viene sovrascritto (override) per fornire un comportamento specifico per i cani.

Ereditarietà multipla

Python supporta anche l’ereditarietà multipla, dove una classe derivata può ereditare da più classi base:

class A:
      def metodo_a(self):
        returnMetodo A

class B:
     def metodo_b(self):
        returnMetodo B

class C(A, B):
        pass

oggetto = C()
print(oggetto.metodo_a()) # Output: Metodo A
print(oggetto.metodo_b()) # Output: Metodo B

In questo esempio, la classe C eredita da entrambe le classi A e B, e quindi ha accesso ai metodi di entrambe. L’ereditarietà è un potente strumento per modellare relazioni tra oggetti e per promuovere il riutilizzo del codice.

EREDITARIETA’ IN PYTHON LINK AL CODICE GITHUB

GITHUB

EREDITARIETA’ IN PYTHON LINK AI POST PRECEDENTI

PREVIOUS POST LINKS