Object Oriented Programming - Dipartimento di Matematica · 2019-12-05 · Object Oriented vs...

Post on 19-Jul-2020

7 views 0 download

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