La programmazione orientata agli oggetti¶
Come definire e usare una nuova classe di oggetti.
Parlando dei dati Python ho spesso usato il termine “oggetto”. Il termine non
era casuale, tutto in Python è un oggetto. Gli oggetti sono delle entità
formate da dati e algoritmi strettamente collegati tra di loro. I dati
dell’oggetto, che rappresentano il suo stato, sono detti attributi, gli
algoritmi che permettono di far funzionare l’oggetto sono detti metodi. In
generale chi usa un oggetto non deve sapere come è organizzato al suo interno,
quali sono i suoi attributi e quali algoritmi lo fanno funzionare, ma deve solo
conoscere la sua interfaccia, cioè i metodi che permettono all’oggetto di
interagire con gli altri oggetti. Gli oggetti sono elementi di una classe: una
stringa è un oggetto della classe str
, una particolare lista è un oggetto
della classe list
, ...
Nella programmazione orientata agli oggetti, una parte del lavoro consiste nel definire le classi. Una caratteristica importante delle classi è quella di ereditare da altre classi attributi e metodi. In questo modo si possono avere intere famiglie di classi imparentate tra di loro.
Come esempio costruiremo la classe delle frazioni facendola derivare dalla
classe madre di tutte le classi: object
. Il primo metodo che forniremo alla
classe sarà il metodo __init__(...)
che viene chiamato quando si crea un
nuovo oggetto di questa classe:
class Frazione(object):
def __init__(self, num, den):
self.num=num
self.den=den
Alcune osservazioni:
- La prima riga dichiara che stiamo definendo una classe che si chiama
Frazione e che discende dalla classe
object
. - Tutta la definizione della classe deve essere indentata.
- Il metodo
__init__
ha un primo parametro convenzionalmente indicato conself
che contiene il riferimento al particolare oggetto. Poi altri due parametri i cui valori vengono associati agli attributiself.num
eself.den
.
Creiamo il nostro primo oggetto della classe Frazione:
>>> f1=Frazione(4, 6)
>>> print f1
<__main__.Frazione object at 0xb6e00bec>
Funziona, ma non ci dice molto... Aggiungiamo un altro metodo con un nome
convenzionale: il metodo __str__
verrà chiamato tutte le volte ci sarà la
necessità di convertire Frazione in stringa:
def __str__(self):
return "%s/%s" % (self.num, self.den)
>>> f1=Frazione(4, 6)
>>> print f1
4/6
Il risultato è già più carino! La prima operazione che ci hanno insegnato a
eseguire con le frazioni è la riduzione ai minimi termini. Per farlo abbiamo
però bisogno di una funzione che, dati due numeri restituisca il massimo comun
divisore (abbiamo già incontrato un’implementazione di questa funzione) e
modifichiamo anche il metodo __init__
in modo che dopo aver definito il
numeratore e il denominatore riduca ai minimi termini la frazione:
def __init__(self, num, den):
self.num=num
self.den=den
self.riduci()
def riduci(self):
def macodi(a, b):
while a<>b:
if a>b: a-=b
else: b-=a
return a
d=macodi(self.num, self.den)
self.num/=d
self.den/=d
>>> f1=Frazione(4, 6)
>>> print f1
2/3
Aggiungiamo i metodi per addizionare e moltiplicare le frazioni:
def __add__(self, altra):
return Frazione(self.num*altra.den+self.den*altra.num,
self.den*altra.den)
def __mul__(self, altra):
return Frazione(self.num*altra.num,
self.den*altra.den)
>>> f1=Frazione(3, 6)
>>> f2=Frazione(4, 10)
>>> print "%s + %s = %s; %s * %s = %s" % (f1, f2, f1+f2, f1, f2, f1*f2)
1/2 + 2/5 = 9/10; 1/2 * 2/5 = 1/5
Alcune osservazioni:
- All’interno del metodo riduci è definita la funzione
macodi(a, b)
, effettivamente serve solo per ridurre ai minimi termini e quindi non è necessario che sia vista dall’esterno. - I metodi
__add__
e__mul__
non hanno bisogno di ridurre ai minimi termini perché questo viene fatto al momento della creazione di una nuova frazione. - I metodi
__add__
e__mul__
vengono chiamati quando in un’espressione deve essere eseguita l’addizione o la moltiplicazione tra due oggetti di questa classe.
Riassumendo
- L’istruzione
class
permette di creare una nuova classe. - Una classe è formata dall’unione di dati, gli attributi e algoritmi, i metodi.
- Un metodo particolare è
__init__
che viene eseguito quando viene costruito l’oggetto. - Il metodo
__str__
viene eseguito quando l’oggetto deve essere convertito in stringa.
Prova tu
- La classe precedente non funziona se uno dei termini è 0, risolvi questi casi.
- Aggiungi i metodi per eseguire sottrazioni e divisioni.