L'ereditarietà ci permette di creare una nuova classe a partire da una classe esistente e di estenderla o modificarla.
Ad esempio, possiamo creare una classe Person
nel modo seguente:
>>> # definiamo una classe Person
>>> class Person:
... # definiamo un __init__ che assegna nome e cognome all'istanza
... def __init__(self, name, surname):
... self.name = name
... self.surname = surname
... # definiamo un metodo "eat" che stampa un messaggio
... def eat(self, food):
... print(self.name, 'is eating', food)
... # definiamo un metodo "sleep" che stampa un messaggio
... def sleep(self):
... print(self.name, 'is sleeping')
...
>>> # creiamo un'istanza di Person specificando nome e cognome
>>> p = Person('Ezio', 'Melotti')
>>> # verifichiamo il valore degli attributi name e surname
>>> e.name
'Ezio'
>>> e.surname
'Melotti'
>>> # verifichiamo che i metodi funzionino
>>> p.eat('pizza')
Ezio is eating pizza
>>> p.sleep()
Ezio is sleeping
Se ora volessimo creare una versione più specializzata di Person
, possiamo definire una nuova sottoclasse Employee
che eredita dalla classe base Person
. Per indicare che Employee
eredita da Person
, basta aggiungere il nome della classe base (o delle classi, nel caso dell'ereditarietà multipla) tra parentesi dopo il nome della sottoclasse:
>>> # definiamo una classe Employee che eredita da Person
>>> class Employee(Person):
... # definiamo un nuovo __init__ che accetta nome/cognome/lavoro
... def __init__(self, name, surname, job):
... # chiamiamo l'__init__ della classe base (o superclasse)
... # che assegna nome e cognome all'istanza
... super().__init__(name, surname)
... # assegniamo il lavoro all'istanza
... self.job = job
... # definiamo un metodo aggiuntivo che stampa un messaggio
... def work(self):
... print(self.name, 'is working as a', self.job)
...
# creiamo un'istanza di Employee specificando nome/cognome/lavoro
>>> e = Employee('Ezio', 'Melotti', 'developer')
>>> # verifichiamo il valore degli attributi name e surname
>>> e.name
'Ezio'
>>> e.surname
'Melotti'
>>> # verifichiamo il valore del nuovo attributo "job"
>>> e.job
'developer'
>>> # verifichiamo che i metodi ereditati da Person funzionino
>>> e.eat('pizza')
Ezio is eating pizza
>>> e.sleep()
Ezio is sleeping
>>> # verifichiamo che il nuovo metodo funzioni
>>> e.work()
Ezio is working as a developer
Dall'esempio possiamo vedere che per definire una sottoclasse basta usare la sintassi class SottoClasse(SuperClasse): ...
o class SottoClasse(SuperClasse1, SuperClasse2, ...): ...
nel caso dell'eredità multipla.
La sottoclasse erediterà automaticamente tutti i metodi e gli attributi definiti dalla classe base (o superclasse), come ad esempio i metodi Person.eat
e Person.sleep
.
È anche possibile, nella sottoclasse, sovrascrivere (override in inglese) e quindi ridefinire metodi definiti dalla superclasse. Per esempio, la sottoclasse Employee
sovrascrive l'__init__
definito dalla classe Person
, modificandolo in modo che accetti un argomento aggiuntivo (job
). Se stiamo sovrascrivendo un metodo, è possibile usare la funzione built-in super()
(che restituisce un riferimento alla classe base) per accedere al metodo corrispondente definito nella classe base. Infine, è possibile definire metodi aggiuntivi (come Employee.work
).
Il risultato finale è una classe Employee
che ha tre attributi (name
, surname
, e job
), un __init__
modificato per accettare un argomento aggiuntivo (job
), due metodi ereditati da Person
(Person.eat
e Person.sleep
) e un nuovo metodo (Employee.work
).