INHERITANCE

The first thing to say about inheritance in Python is that the language allows one class to inherit the attributes and methods of another class. Subclasses or derived classes that are the most specialized inherit attributes and methods from their base classes or superclasses. Derived classes can override the behavior of inherited attributes (methods) and can add additional functionality that tends to specialize the class. Superclasses are generally more generic than their subclasses. When we create an instance of a subclass, this is also an instance of all the superclasses of the class of which it is an instance.

THE ISINSTANCE FUNCTION

There is an isinstance function that takes the instance as its first parameter and the class you want to verify as its second parameter. The function returns True if it is an instance of it. False otherwise. m1 being an instance of AClass is also implicitly an instance of BClass, moreover m1 inherits from BClass both the __init_ constructor and the printMessage(self) instance method as can be seen from the example.

Inheritance

OVERRIDE

With the override we can redefine the attributes (methods) in the subclasses. In the AClass derived class we are redefining the behavior of printMessage(self) albeit in a minimal way. When we create an instance of AClass that we call m1 and call printMessage(self) we are actually calling the method of the derived class as we have overwritten that of the base class. However, the code we wrote has a problem. If we also create a constructor in the derived class, the subclass constructor will be invoked when the instance is created, the superclass constructor will be ignored by not setting the message attribute correctly. This is because the superclass constructor is overridden. To solve this problem we use the super() function.

Override

THE SUPER() FUNCTION

super() allows us to access superclass methods from subclasses. The super() function causes the superclass constructor to be executed, so by appropriately passing the message attribute, which we receive in the subclass constructor, all attributes will be initialized correctly.

The super() function

PROPERTIES

Normally in Object Oriented languages there is a tendency to encapsulate or make private the data with getter and setter methods and make the methods public where necessary. Python does not fully support encapsulation. They can be created using a property’s getter and setter decorators.

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()

DEEPENING

Inheritance is a fundamental concept in object-oriented programming (OOP) in Python. It allows you to create a new class (derived class) that inherits attributes and methods from another class (base or parent class). This allows code to be reused and the functionality of existing classes to be extended.

Key concepts.

-Base (Parent) Class: The class from which attributes and methods are inherited.

-Derived Class (Child): The class that inherits from the base class.

Base syntax

Here is an example of how inheritance works 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.

Explanation

1. Base Class (Animale): We define a class called Animale with a nome attribute and a parla method that returns a generic string.

2. Derived Class (Cane): The class Cane inherits from the class Animale. The super() function is used to call the constructor of the base class (__init__), allowing the derived class to initialize the attributes of the base class.

3. Method Overrides: In the Cane class, the parla method is overridden (override) to provide dog-specific behavior.

Multiple Inheritance.

Python also supports multiple inheritance, where a derived class can inherit from multiple base classes:

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 this example, class C inherits from both classes A and B, and thus has access to the methods of both. Inheritance is a powerful tool for modeling relationships between objects and promoting code reuse.

INHERITANCE IN PYTHON LINK TO THE GITHUB CODE

GITHUB

INHERITANCE IN PYTHON LINK TO PREVIOUS POST

PREVIOUS POST LINKS