In [1]:
a = 2 + 3j
print(a, type(a))
Vediamo ora come aggiungere un nuovo tipo che sia una nostra implementazione di un numero complesso. Una possibile implementazione di base è la seguente. Si noti che qualsiasi oggetto in Python eredità dall'oggetto base object
.
ESERCIZIO 1: Completare il metodo somma
nel codice seguente.
In [ ]:
class NumeroComplesso(object):
def __init__(self, real, imag):
"""Metodo costruttore, chiamato quando viene
inizializzato un nuovo oggetto"""
self.a = real
self.b = imag
def somma(self, c):
"""Somma al numero corrente il numero complesso c"""
# DA COMPLETARE
pass
def __str__(self):
"""Ritorna una stringa che rappresenta il numero"""
return str(self.a) + ' + ' + str(self.b) +'i'
In [ ]:
type(NumeroComplesso)
In [ ]:
a = NumeroComplesso(2,3)
b = NumeroComplesso(1,-2)
print(a)
a.somma(b)
print(a)
In [ ]:
a.a = 0
a.somma(b)
print(a)
Supponiamo ora di definire un nuovo tipo chiamato NCO
che rappresenta un numero complesso, ma su cui vogliamo specificare l'overloading di due operazione:
Per specificare che la classe NCO
estende la classe base NumeroComplesso
basta dichiararla come:
class NCO(NumeroComplesso):
Si notiche si è racchiuso tra parentesi il nomde del tipo da cui si ereditano attributi e metodi.
ESERCIZIO 2: Si completi il metodo __add__
nella classe NCO
in modo che restituisca un nuovo oggetto che, dati due numeri a
e b
, rappresenti il numero complesso c = a + b
.
In [ ]:
class NCO(NumeroComplesso):
# EREDITA DI I METODI E ATTRIBUTI DELLA CLASSE "NUMERO COMPLESSO"
def __add__(self, c):
"""Esempio di OPERATOR OVERLOADING: addizione"""
# DA COMPLETARE
pass
def __eq__(self, c):
"""Esempio di OPERATOR OVERLOADING: confronto"""
return self.a == c.a and self.b == c.b
In [ ]:
c = NCO(1,2)
print(c)
In [ ]:
type(c.somma)
In [ ]:
type(c.a)
In [ ]:
a == c
In [ ]:
d = NCO(1,2)
print(c, id(c))
print(d, id(d))
print(d == c)
In [ ]:
# Definizione di una classe che implementa un "adder"
class Adder(object):
def __init__(self, n=0):
self.n = n # Stato mutabile della classe (DANGER ZONE!!!)
def __call__(self, m):
return self.n + m
add5_istanza = Adder(5)
print(add5_istanza(1), add5_istanza(7))
In [ ]:
# Definizione di una closure che implementa un "adder"
def make_adder(n=0):
def adder(m):
return n + m
return adder
add5_function = make_adder(5)
print(add5_function(1), add5_function(7))
In [ ]:
add5_istanza.n = 1
print(add5_istanza(1), add5_istanza(7))
print(add5_function(1), add5_function(7))
NOTA: Con gli oggetti per poter capire l'esecuzione del codice bisogna capire qual'è stata la storia di esecuzione precedente...
In [ ]:
# Definizione di una classe che implementa un "counter"
class Counter(object):
def __init__(self, n=0):
self.n = n
def __call__(self):
self.n += 1
return self.n
counter_istanza = Counter(5)
print(counter_istanza(), counter_istanza())
In [ ]:
# Definizione di una closure che implementa un "counter"
def make_counter(n=0):
def state():
c = n
while True:
c += 1
yield c
def counter():
return next(f)
f = state()
return counter
counter_function = make_counter(5)
print(counter_function(), counter_function())
In [ ]:
# faccio una modifica apparentemente "innocua"
counter_istanza.n = 'ciao'
In [ ]:
print(counter_function(), counter_function())
In [ ]:
# ... dopo un po` riutilizzo il counter_istanza
print(counter_istanza())
In [ ]: