Object Oriented Programming - Dipartimento di Matematica · 2019-12-05 · Object Oriented vs...
Transcript of Object Oriented Programming - Dipartimento di Matematica · 2019-12-05 · Object Oriented vs...
OOP: Object Oriented Programming
Riferimento: Capitolo 8 del testo di Python consigliato“Classes and object oriented programming”
Documentazione online:https://docs.python.org/3.6/tutorial/classes.html
OOP: Idea Principale
L’idea principale della programmazione orientate agli oggettiè di pensare agli oggetti come delle collezioni sia di dati chedi funzioni che operano su quell specific tipo di dati.
Gli oggetti sono una caratteristica dominante di Python: ognioggetto ha un tipo che definisce le operazioni che un programma può eseguire su quell’oggetto.
Abbiamo visto come definire nuove funzioni, ora vediamocome definire nuovi TIPI
Esempi: list, string, dictionary, tuple, set, …
Esempio: Numeri Complessi
Tipo: Numero complesso
Dati: due numeri reali, la parte reale e quella immaginaria
Operazioni: somma, stampa a video, calcolo del coniugato
La specifica delle operazioni possibili definisce unainterfaccia tra i dati ed il resto del programma.
Il modo in cui viene calcolato il coniugato di un numerocomplesso (l’algoritmo usato e la sua implementazione) viene nascosto al resto del programma (ENCAPSULATION)
Abstract Data TypesUn Abstract Data Type (ADT) è un insieme di oggetti e di operazioni sugli oggetti stessi
Operazioni ed oggetti sono raggruppati in modo chepossano essere passati da una parte all’altra del programma
Due concetti chiave della programmazione sono:
1. DECOMPOSITION: viene usata per creare una struttura nelnostro programma
2. ABSTRACTION: si cerca di eliminare i dettagli menoimportanti per concentrarsi sugli aspetti fondamentali di un problema
ESEMPIO: pensare sempre ai numeri complessi, quandovengono passati ad una funzione
Listehttps://docs.python.org/3/tutorial/datastructures.html
Stringhe
Dizionari
Operazioni su ClassiUna classe supporta due tipi di operazioni:
1. Istanziazione: viene usata per creare una nuova istanzadella classe, ovvero un nuovo oggetto del tipo definito dallaclasse stessa. Quando viene creato un nuovo oggetto vienesempre richiamato il suo metodo costruttore: __init__(…)
2. Riferimento ai suoi attributi (metodo selettori) : si usa la “dot notation” per acceddere agli attributi e metodi dellaclasse
ATTENZIONE: l’oggetto associato all’espressione che precede il‘dot’ viene implicitamente passato come primo parametro del metodo, e viene chiamato, per convenzione, sempre self(Vedi notebook)
Classi
Un Abstract Data Type (ADT) è un insieme di oggetti e di operazioni sugli stessi oggetti. In Python, si implementanonuovi ADT definendo nuove classi
class NumeroComplesso(object):
def __init__(self, real, imag):
""" Metodo costruttore, chiamato quando viene
inizializzato un nuovo oggetto """
self.a = real
self.b = imag
Classi
Un Abstract Data Type (ADT) è un insieme di oggetti e di operazioni sugli stessi oggetti. In Python, si implementanonuovi ADT definendo nuove classi
class NumeroComplesso(object):
def __init__(self, real, imag):
""" Metodo costruttore, chiamato quando viene
inizializzato un nuovo oggetto """
self.a = real
self.b = imag
def __str__(self):
""" Ritorna una stringa che rappresenta il numero """
return str(self.a) + ' + ' + str(self.b) +'i'
Classi
Un Abstract Data Type (ADT) è un insieme di oggetti e di operazioni sugli stessi oggetti. In Python, si implementanonuovi ADT definendo nuove classi
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 """
self.a = self.a + c.a
self.b = self.b + c.b
def __str__(self):
""" Ritorna una stringa che rappresenta il numero """
return str(self.a) + ' + ' + str(self.b) +'i'
Metodi con underscore __XX__In Python esistono diversi metodi che possono esseredefiniti con un doppio underscore prima e dopo il nomedel metodo, tipo __init__(…)
ALTRI ESEMPI:
• __str__(self): restiruisce una stringa, e viene per esempio chiamato in automatic quando un oggetto vienepassatto alla funzione print()
• __add__(self, other): viene utilizzato per fare l’OVERLOADING dell’operatore di addizione ‘+’
• __eq__(self, other): viene utilizzato per fare l’OVERLOADING dell’operatore di confronto ‘==’
• __call__(self): viene chiamata quando si richiamaun oggetto direttamente (vedi esempio nel notebook)
Metodi con underscore __XX__
Metodi con underscore __XX__
Documentazione online con tutti i possibili metodi di overloading:https://docs.python.org/3/reference/datamodel.html
Inheritance
L’EREDITARIETÀ offre un meccanismo per costruire gruppidi tipi (classi) collegati tra loro attraverso una strutturagerararchica
In pratica permette di costruire una gerarchia di tipi, in cui un tipo di dati (subclass) può ereditare tutti gli attributi e metodi dal tipo da cui deriva (la sua superclass)
Si veda il notebook Lab 14 per un semplice esempio con inumeri complessi, per maggiori dettagli si rimanda al Capitolo 8 del libro di riferimento.
Object Oriented vs Functional Programming
L’uso di ADT incoraggia l’analista programmatore a pensarepiù in termini di OGGETTI piuttosto che di FUNZIONI
Un programma diventa una collezione di TIPI invece cheuna collezione di FUNZIONI
Definizione di una classe: Sintassiclass <NomeNuovoTipo>(object):
def __init__(self, n):
self.<attributo1> = n
self.<attributo2> = ‘prova’
def __str__(self):
return “NuovoTipo ”+ self.<attributo2>
def <metodo1>(self, b):
# esempio codice da eseguire…
return self.attributo1 + b
Definizione di una classe: Sintassi# Esempio di definizione oggetto
Obj = NomeNuovoTipo(3) # Costruttore
print(Obj.attributo1, Obj.attributo2) # Selettoriprint(Obj.metodi1(4))
class <NomeNuovoTipo>(object):
def __init__(self, n):
self.<attributo1> = n
self.<attributo2> = ‘prova’
def __str__(self):
return “NuovoTipo ”+ self.<attributo2>
def <metodo1>(self, b):
# esempio codice da eseguire…
return self.attributo1 + b
Due funzioni utili: getattr e setattr
# Esempio di definizione oggetto
Obj = NomeNuovoTipo(3)
print(getattr(Obj, attributo1, ‘default’)
# Quasi equivalente a:
# print(Obj.attributo1)
print(setattr(Obj, nuovoAttributo, 13)
# Quasi equivalente a:
# Obj.nuovoAttributo = 13
Tema d’esame di giugno# Esercizio 3: Class definition
class Flower(object):
def __init__(self, row):
self.sepalLength = float(row[0])
self.sepalWidth = float(row[1])
self.petalLength = float(row[2])
self.petalWidth = float(row[3])
self.species = row[4]
def __lt__(self, b):
return self.sepalLength < b.sepalLength
def __eq__(self, b):
return self.species == b.species
def __str__(self):
return "specie: {}, lun petalo: {}, lun sepalo: {}, lar petalo: {}, lar sepalo: {}".format(self.species, self.petalLength, self.sepalLength, self.petalWidth, self.sepalWidth)
# Esempio di utilizzo della classe Flower
# Con la riga sotto viene richiamato il costruttore __init__ di Flower
fiore1 = Flower([‘2.1’,’4.2’,’31.0’,’3.0’,’rosa’])
fiore2 = Flower([‘4.1’,’3.2’,’21.0’,’7.0’,’rosa’])
# Con la riga sotto viene richiamato il metodo __str__ di Flower
print(fiore1)
# Con la riga sotto viene richiamato il metodo __eq__ di Flower
# nel modo seguente: fiore1.__eq__(fiore2)
# che e’ equibalente a: __eq__(fiore1, fiore2)
print(fiore1 == fiore2)
# Con la riga sotto viene richiamato il metodo __lt__ di Flower
# nel modo seguente: fiore1.__lt__(fiore2)
# che e’ equibalente a: __lt__(fiore1, fiore2)
if fiore1 < fiore2:
print(“fiore1 e’ piu’ piccolo”)
Esempio 1: Adder
ESEMPIO: Definire un tipo di dato che memorizza un numero intero x (che di default vale zero), e ogni volta cheviene richiamato come se fosse una funzione tramite ilmetodo __call_(self, y), restituisce il valore (x+y).
• Una classe rappresenta dei “dati con delle operazionicollegate”
• Una closure rappresenta delle “funzione con dei daticollegati”
ESEMPIO: vedi notebook Lab 14
Esempio 2: Counter
ESEMPIO: Definire un tipo di dato che conta a partire da un dato numero x, ovvero che ogni volta che vienerichiamato incrementa x di uno e restituisce il nuovo valore di x
• Una classe rappresenta dei “dati con delle operazionicollegate”
• Una closure rappresenta delle “funzione con dei daticollegati”
ESEMPIO: vedi notebook
Esempio 3: Range
MOTIVAZIONE:Ls = list(range(2,1000000000,2))
sum(Ls)
Oppure:sum(range(2, 1000000000, 2))
ESEMPIO: Definire un tipo di dato che emula il comportamentodel range(start, stop, step) di Python.
• Una classe rappresenta dei “dati con delle operazionicollegate”
• Una closure rappresenta delle “funzione con dei dati collegati”
Esempio 3: MyRange
Containers, Generators, e Iterators
Lazy Fibonacci
ESERCIZIO: scrivere una funzione layz cherestituisce un generatore che genera la sequenza di Fibonacci (ovvero, che ad ogni chiamata di next() restituisce il prossimo numero delle sequenza di Fibonacci)
Lazy Fibonacci
def LazyFibonacci():
prev, curr = 0, 1
while True:
yield curr
prev, curr = curr, prev + cur
Lazy Fibonacci
def LazyFibonacci():
prev, curr = 0, 1
while True:
yield curr
prev, curr = curr, prev + cur
ESERCIZIO: come implementare un oggetto che realizzalo stesso comportamento di LazyFibonacci?
PARTE SECONDA:
HANDLING EXCEPTIONS
Sino ad ora abbiamo visto le Exceptions come a degli erroriche causano un’interruzione “brutale” del nostroprogramma. Esempi visti a lezione:
• ValueError: invalid literal for int() with base 10: '3.0'
• AttributeError: readonly attribute (z.real = 3)
• NameError: name 'x' is not defined (dopo del x)
• TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int‘
• TypeError: 'int' object is not iterable
• StopIteration: chiamata a next() su un iteratore vuoto
Handling Exceptions 1/4
• ValueError: invalid literal for int() with base 10: '3.0'
• AttributeError: readonly attribute (z.real = 3)
• NameError: name 'x' is not defined (dopo del x)
• TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int‘
• TypeError: 'int' object is not iterable
• StopIteration: chiamata a next() su un iteratore vuoto
Handling Exceptions 2/4
Questi sono tutti esempi di eccezioni generate dal sistema per gestire ERRORI in
parte prevedibili del programma.
Gli errori precedenti sono generate dal commando
raise ValueError(‘Vostro msg errore in dialetto’)
E possono essere gestiti tramite i comandi
try:
ChiamataFunzione()
except ValueError:
print(‘decidete voi cosa fare, ma no crash!’)
Handling Exceptions 3/4
Documentazione con tutte le possibili eccezioni:https://docs.python.org/3/library/exceptions.html
Questi sono tutti esempi di eccezioni generate dal sistema per gestire ERRORI in parte prevedibili del programma. Gli erroriprecedenti sono generate dal comando
raise ValueError(‘Vostro msg errore’)
E possono essere gestiti tramite i comanditry:
ChiamataFunzione()
except ValueError:
print(‘decidete voi cosa fare, ma no crash!’)
Handling Exceptions 4/4
LE ECCEZIONI SONO UN MODO PER SEMPLIFICAREIL FLUSSO DEL PROGRAMMA (LO SONO??)
Errore o flusso di programma?try:
D[key] = D[key] + value
except Exception:
D[key] = value
Forse era meglio usare il metodo “giusto”:
D[key] = value + D.get(key, 0)
Esempio con i dizionari
Leggete la documentazione!
Documentazione con tutte le possibili ECCEZIONI:https://docs.python.org/3/library/exceptions.html
Documentazione con tutti i possibili METODI DI OVERLOADING:https://docs.python.org/3/reference/datamodel.html
Documentazione sulle CLASSI:https://docs.python.org/3.6/tutorial/classes.html
Documentazione sulle LISTE:https://docs.python.org/3/tutorial/datastructures.html