91
1 Programmazione Orientata agli Oggetti Programmazione Orientata agli Oggetti e Scripting in Python e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università degli Studi di Cagliari

Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

  • Upload
    others

  • View
    16

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

1

Programmazione Orientata agli Oggetti Programmazione Orientata agli Oggetti e Scripting in Pythone Scripting in Python

Paradigma ad Oggetti - 1

DIEE Univ. di Cagliari

DIEE - Università degli Studi di Cagliari

Page 2: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

2

Outline

Introduzione: riassunto caratteristiche OO

Classi

Metodi

Attributi

Creazione/inizializzazione

Eredità e overriding

Information Hiding

Property

Attributi e metodi speciali (overloading di funzioni e operatori)

Page 3: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

3

Introduzione

Il Python è un linguaggio che supporta diversi paradigmi/stili di programmazione:

procedurale

funzionale

a oggetti

meta-programmazione

scripting

Page 4: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

4

Riassunto funzionalità O.O.

ereditarietà: multipla

dispatching: singolo (un oggetto è proprietario del metodo, eventualmente tramite la classe)

binding: dinamico (e il controllo di esistenza di un metodo/attributo è fatto a run-time)

information hiding: forma "debole" di privatezza e property

polimorfismo: overriding e coercion (esplicita ed implicita)

Page 5: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

5

Classi

Una classe è un oggetto che permette di creare altri oggetti (modello “object-factory”)

Gli oggetti creati sono definiti istanze della classe

Per definire una classe, è possibile seguire due approcci:

old-style

new-style

Page 6: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

6

Classi “old-style”

Non derivano da alcuna classe base; saranno abbandonate nelle prossime revisioni del linguaggio.

Sintassi generale: class MyClass():

pass

#oppure

class MyClass:pass

Page 7: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

7

Classi “new-style”

Derivano tutte, direttamente o indirettamente, dalla classe base object

Il fatto di ereditare da una classe base permette di avere delle funzionalità e comportamenti comuni in tutte le classi della gerarchia

Sintassi generale:

class MyClass(object): pass myobj = MyClass() # costruttore

Page 8: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

8

Classe object

object

list str dict

mylist MyClass

Page 9: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

9

Classe object

object è la classe di base da cui ereditano tutti i tipi built-in (list, dict, str...)

Una classe può ereditare direttamente o indirettamente da object, ad esempio:

class MyClass(object):

...

class MyList(list):

...

Page 10: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

10

Metodi

Esistono tre tipi di metodi definibili in una classe:

di istanza

di classe

Statici

Page 11: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

11

Metodi di istanza

Sono definiti come funzioni dentro il corpo di una classe

Il primo argomento è il riferimento all'oggetto che rappresenta l'istanza (self):class P(object):

...

def method(self):

print 'metodo di P'

instance = P()

instance.method()

Page 12: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

12

Metodi di istanza:self

self è sempre esplicito nella definizione del metodo, a differenza di C++ e Java, in cui this è passato implicitamente.

La sintassi della chiamata del metodo sull'istanza è invece analoga a quella di Java e C++

Nota: il nome self è solitamente usato per convenzione, ma potrebbe essere utilizzato un altro nome

Page 13: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

13

Metodi di istanza

I metodi di istanza sono dei metodi della classe che si applicano alle istanze:

class C(object):

def m(self): pass

x = C()

x.m() è interpretato come C.m(x)

il primo parametro deve essere necessariamente un oggetto di tipo C(ad esempio, C.m(10) sarebbe errato)

Page 14: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

14

Metodi di classe

Un metodo di classe è un metodo che si applica alla classe stessa

Viene passato implicitamente un parametro, chiamato per convenzione cls, che rappresenta la classe:

class P(object):

...

def cmethod(cls):

print cls.__name__, 'chiama cmethod'

cmethod = classmethod(cmethod)

P.cmethod()

Page 15: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

15

Metodi di classe

Un metodo di classe si genera a partire da un metodo di istanza o da una funzione tramite classmethod

In pratica, si sovrascrive il riferimento ad un metodo di istanza con un riferimento ad un metodo di classe che ha lo stesso nome:

cmethod = classmethod(cmethod)

Page 16: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

16

Metodi di classe

E' possibile una sintassi alternativa, che sfrutta i decorators:

class P(object):

... @classmethod

def cmethod(cls):

print cls.__name__, 'chiama cmethod'

Page 17: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

17

Metodi di classe

I metodi di classe possono essere chiamati sia dalla classe che da un'istanza della classe

Il riferimento alla classe viene passato come parametro implicito

Nota: non esiste un equivalente in C++/Java (non esiste per questi linguaggi un oggetto che rappresenta la classe!)

p = P()

P.cmethod() # le due chiamate sono

p.cmethod() # equivalenti

Page 18: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

18

Metodi statici

Un metodo statico si comporta come una funzione globale dentro il namespace della classe.

Sono simili ai metodi statici di Java e C++, tuttavia non è possibile chiamarli su un'istanza:

class P(object):

...

def smethod():

print ''

smethod = staticmethod(smethod)

P.smethod()

Page 19: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

19

Metodi statici

Un metodo statico si genera a partire da un metodo di istanza o da una funzione tramite staticmethod

La sintassi per definire un metodo statico è analoga a quella vista per i metodi di classe

smethod = staticmethod(smethod)

Oppure:

@staticmethod

def smethod()

Page 20: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

20

Metodi statici

I metodi statici possono essere chiamati solo dalla classe e non dall'istanza

Non viene passato nessun parametro implicito al metodo! (non hanno quindi riferimento né alla classe né all'istanza)

Equivalgono a delle normali funzioni dentro il namespace della classe

P.smethod()

P().smethod() # sbagliato

Page 21: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

21

Creazione/inizializzazione

A differenza di altri linguaggi (C++/Java), gli oggetti sono costruiti e inizializzati in due passi successivi separati:

creazione funzione membro statica __new__

inizializzazionefunzione membro di istanza __init__

Page 22: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

22

__new__

La funzione __new__ crea e restituisce una nuova istanza di una classe non ancora inizializzata

E' richiamata automaticamente in fase di creazione di un'istanza di classe

Se non trovata, si risale la gerarchia fino a object. Esempio:

myobj = MyClass(...)

equivale a: myobj = MyClass.__new__(...)

myobj.__init__(...)

Page 23: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

23

__new__

Sovrascrivendo la funzione __new__ si possono ottenere dei comportamenti molto particolari. Per esempio:

__new__ può restituire un oggetto già creato

__new__ può costruire un oggetto di una classe diversa da quella attuale

Solo in rari casi si ha effettivamente l'esigenza di riscrivere __new__ (In pratica si usa sempre la __new__ fornita dalla classe object).

Page 24: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

24

__new__ example

class MYClass(object): def __new__(cls,x,y): print 'redefined the new class method' ob=object.__new__(cls,x,y) return ob def __init__(self,x,y): self.x=x self.y=y

Page 25: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

25

__init__

La funzione __init__ inizializza l'istanza (oggetto) appena creata da __new__

Viene chiamata immediatamente dopo __new__

Nel caso più semplice, l'inizializzazione aggiunge alcuni attributi all'istanza stessa:

class MyClass(object): def __init__(self): self.x = 10 myobj = MyClass() print myobj.x # stampa 10

Page 26: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

26

__init__

__init__, come tutte le funzioni, può avere un numero arbitrario di parametri in ingresso che possono essere usati per l'inizializzazione. Esempio:

class MyClass(object):

def __init__(self,x,y):

self.x = x

self.y = y

Page 27: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

27

Attributi

Possono essere:

di istanza

di classe

Page 28: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

28

Attributi

C++ e Javagli oggetti hanno un numero e un tipo di attributi predeterminati dalla classe.

Pythonoggetti della stessa classe possono avere attributi differenti__init__ serve solo per inizializzare ma non vincola il numero di attributi di un oggetto.

Page 29: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

29

Attributi di istanza

L'aggiunta/rimozione/modifica di attributi può avvenire in qualunque momento durante la vita dell'oggetto

class MyClass(object):

def __init__(self):

self.x = 10 # aggiunta di x

myobj = MyClass()

myobj.y = 20 # aggiunta di y

del myobj.x # rimozione di x

myobj.y = 300 # modifica di y

Page 30: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

30

Attributi di istanza

class MyClass(object):

def __init__(self):

self.x = 10

o1,o2 = MyClass(), MyClass()

o2.y=20

del o2.x

Page 31: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

31

Attributi di classe

Anche le classi sono oggetti su cui è possibile aggiungere degli attributi

In questo caso, si parla di attributi di classe

class P(object):

a = 20

P.b = 10

print P.a, P.b # a,b sono attributi di # classe

Page 32: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

32

Attributi di classe

Il modo più semplice di dichiarare un attributo di classe è assegnargli un valore nel corpo della classe

Agli attributi di classe si può accedere anche tramite le singole istanze

class P(object):

a = [1,2,3]

P.a += [4];

P().a += [5];

Page 33: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

33

Eredità

Python supporta il meccanismo dell'eredità, che può essere:

singola

multipla

Page 34: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

34

Eredità Singola

Eredità singola

C

B

A

object

D

Page 35: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

35

Eredità Singola

Il caso di eredità singola è quello più semplice

class C(object): pass

class B(C): pass

class D(C): pass

class A(B): pass

print [cls.__name__ for cls in A.__mro__]

['A', 'B', 'C', 'object']

Page 36: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

36

__mro__

__mro__ stands for Method Resolution Order. It returns a list of types the class is derived from, in

the order they are searched for methods.

Page 37: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

37

Eredità Multipla

Python supporta anche l'ereditarietà multipla:

B C

A

object

D

Page 38: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

38

Eredità Multipla

Esempio di eredità multipla: class B(object):

...

class C(object):

...

class D(object):

...

class A(B,C,D):

... print [cls.__name__ for cls in A.__mro__]

['A', 'B', 'C', 'D' 'object']

Page 39: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

39

Eredità: Metodi

I metodi della classe base sono ereditati dalla classe derivata

I metodi statici e di classe si ereditano con le stesse regole dei metodi di istanza

Se si ridefinisce un metodo, la chiamata al metodo corrispondente della classe base non è automatica

Il metodo di istanza __init__ non fa eccezione: si comporta diversamente dai costruttori di C++ e Java

Page 40: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

40

Eredità:Metodi

class A(object):

def who_am_I(self):

print "I am A"

class B(object):

def who_am_I(self):

print "I am B"

class C(object):

def who_am_I(self):

print "I am C"

class D(C,B,D):

Pass

>>> d=D()

>>> d.who_am_I()

I am C

Page 41: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

41

Eredità: Metodi

class B(object):

def m(self): print 'B.m()'

def sm(): print 'B.sm()'

sm = staticmethod(sm)

def cm(cls): print 'B.cm()'

cm = classmethod(cm)

class D(B):

pass

D().m();

D().cm(); D.sm()

Page 42: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

42

Eredità: Ordine di chiamata

Un metodo richiamato su un oggetto viene cercato in una lista ordinata di classi

La lista è univocamente determinata dalla gerarchia di eredità ed è contenuta nell'attributo di classe read-only __mro__

Nota: __mro__ esiste solo nelle classi derivate (anche se indirettamente) da object!

Page 43: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

43

Eredità: Ordine di chiamata

Nel caso di eredità multipla, si inizializza __mro__ con la lista della classe più a destra; poi si inseriscono (in testa) le liste delle altre classi proseguendo verso sinistra eliminando i duplicati

C

B

A

object

D

Page 44: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

44

Eredità: Ordine di chiamata

Di conseguenza le classi indicate per prime (a sinistra) compariranno nelle prime posizioni della lista

class C(object):pass

class D(object):pass

class B(C):pass

class A(B, D):pass>>>print [cls.__name__ for cls in A.__mro__]

['A', 'B', 'C', 'D', 'object']

Page 45: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

45

Eredità multipla

L'eredità multipla può portare a delle gerarchie molto complesse in cui non è semplice determinare la lista di precedenza nella chiamata dei metodi

Potrebbero verificarsi situazioni non gestibili (ambigue): in tal caso è lanciata un'eccezione

Page 46: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

46

Eredità: Overriding

A differenza di C++/Java la definizione di un metodo nasconde sempre le definizioni precedenti, anche in presenza di un numero diverso di parametri e all'interno della stessa classe (overriding, no overloading in senso stretto)

In un contesto di eredità, un metodo riscritto in una classe figlia nasconde quello della classe base

Il modo più semplice per richiamare un metodo di una classe base è:

def method(self,attr):

Base.method(self,attr)

Page 47: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

47

Eredità: overriding

Spesso un metodo di una sottoclasse deve delegare una parte del lavoro al metodo corrispondente della superclasse.

Un caso tipico è quello dell'__init__: in caso di overriding NON viene richiamato automaticamente quello della classe base ma deve essere richiamato esplicitamente!

class MyList(list):

def __init__(self,L):

list.__init__(self,L)

Page 48: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

48

Eredità: overriding

Questa soluzione può generare dei problemi nel caso di eredità multipla

E' possibile che alcuni metodi della classe base vengano chiamati più di una volta (spesso non è la cosa voluta)

Possibile soluzione: funzione built-in super

Page 49: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

49

Eredità: super

Restituisce un wrapper della superclasse, intesa come classe successiva della gerarchia

Nell'uso più comune è passato un riferimento all'oggetto chiamante: super restituisce infatti l'elemento successivo alla classe corrente nella lista __mro__ della classe dell'oggetto chiamante

Usato opportunamente permette di gestire situazioni di doppia eredità

Page 50: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

50

Eredità: super

class A(object):

def m(self):return "A"

class B(A):

def m(self):return "B" + super(B, self).m()

class C(A):

def m(self):return "C" + super(C, self).m()

class D(C, B):

def m(self):return "D" + super(D, self).m()

>>> print D().m()

DCBA #nota: D.__mro__= [D, C, B, A]

Page 51: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

51

Eredità: Attributi

Gli attributi sono aggiunti/cancellati in maniera dinamica

Non si può parlare di eredità in senso classico degli attributi di istanza

Gli attributi di classe sono sempre ereditati

Una classe può avere o meno gli attributi di istanza della classe base a seconda di come si comporta l'inizializzatore

Page 52: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

52

Eredità: Attributi

Nell'esempio seguente B.__init__ viene ereditato: in fase di costruzione, ad ogni istanza di D verranno aggiunti gli stessi attributi di B.

class B(object):

def __init__(self):

self.x=10

class D(B):

pass

D().x

Page 53: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

53

Eredità: Attributi

Anche in questo caso gli attributi vengono “ereditati” in quanto D.__init__ è ridefinito ma richiama B.__init__.

class B(object):

def __init__(self):

self.x=10

class D(B):

def __init__(self):

B.__init__(self)

D().x

Page 54: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

54

Eredità: Attributi

In questo caso invece non vengono aggiunti attributi in quanto B.__init__ non è richiamato automaticamente.

class B(object):

def __init__(self):

self.x=10

class D(B):

def __init__(self):

pass

D().x # errore

Page 55: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

55

Information Hiding

Gli attributi sono normalmente considerati “pubblici”

Esiste un concetto di “privatezza” molto diverso rispetto a quello di altri linguaggi (visibilità public/private/protected in C++/Java)

Gli attributi che iniziano con __ (privati) sono trattati in maniera speciale dall'interprete, ma l'accesso non è ristretto

Page 56: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

56

Information Hiding

gli attributi speciali iniziano e finiscono con __ e servono per rappresentare funzioni e operatori particolari (__new__, __init__, __add__, __call__, __slots__)

gli attributi privati iniziano con __L'interprete rinomina questi attributi usando il nome della classe di appartenenza

__x -> _ClassName__x

Questo essenzialmente permette alle sottoclassi di usare attributi con lo stesso nome senza modificare il comportamento di eventuali metodi che ne facevano uso

Page 57: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

57

Information Hiding

class MyClass(object):

def __init__(self):

self.__x=10 # membro privato

def getX(self):

return self.__x

def setX(self,value):

self.__x=value

o = MyClass()

print o.getX()

print o._MyClass__x

Page 58: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

58

Property

Consentono di costruire un data descriptor (ossia un “attributo virtuale”) che richiama delle funzioni durante il suo l'accesso (in lettura, scrittura, cancellazione)

Permettono di realizzare l'information hiding mantenendo una sintassi semplice e pulita

Si definiscono richiamando la funzione built-in property:

x = property(fget=None, fset=Nonem fdel=None, doc=None)

Page 59: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

59

Property

class MyClass(object): def __init__(self): self.__x=10 def getX(self): return self.__x def setX(self,value): self.__x=value x=property(fget=getX, fset=setX)

o = MyClass() o.x = 10 # richiama setX print o.x # richiama getX

Page 60: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

60

Property

Nell'esempio precedente non è stato specificato fdel, per cui l'attributo x sarà non cancellabile

In maniera analoga, è possibile definire attributi non modificabili (read-only) e/o non accessibili:

class MyClass(object): def __init__(self): self.__x=10 # non modificabile def getX(self): return self.__x x=property(fget=getX) #read-only o = MyClass(object) o.x = 10 # errore

Page 61: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

61

Property

class MyClass():

def __init__(self):

self.x=0

def delete(self):

del self.x

x=property(fdel=delete)

>>> o=MyClass()

>>> o.x

0

>>> del o.x

Page 62: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

62

Ereditarietà: property

Le property vengono ereditate come se fossero metodi anziché attributirichiamare una property è equivalente chiamare i metodi

fget/fset/fdelnon dipendono in maniera diretta dal comportamento di __init__.

X = property(fget, fset, fdel)

Page 63: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

63

Eredità: property

class Persona(object):

def __init__(self,n):

self.nome = n

def getnome(self):

return self.nome

Nome = property(getnome) # read-only

p = Persona('Mario')

print p.Nome

(continua)

Page 64: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

64

Ereditarietà: property

class Medico(Persona):

def __init__(self):

pass

m = Medico()

print m.Nome # errore!!!

# Nome esiste ma richiama nome che invece non esiste!

Page 65: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

65

Eredità: property

Questo invece funziona. Perché ?

class Persona(object): def __init__(self,n): self.nome = n def getnome(self): return self.nome def setnome(self,n): self.nome = n Nome = property(getnome,setnome) class Medico(Persona): def __init__(self): pass m = Medico() m.Nome = 'Mario' print m.Nome

Page 66: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

66

Attributi e metodi speciali

Tutti gli attributi/metodi che iniziano e finiscono con __ hanno un significato speciale in Python.Abbiamo già visto:

__new__ __init____mro__

altri ...

__class____name____dict____slots__...

Page 67: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

67

Attributi e metodi speciali

__class__

E' un attributo che contiene un riferimento alla classe a cui appartiene l'oggetto. Tutti gli oggetti, comprese le classi, hanno l'attributo __class__

class P(object):

pass

p = P()

p.__class__

Page 68: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

68

Attributi e metodi speciali

__name__

E' un attributo che contiene il nome di una classe. Tutte le classi (non le istanze!), comprese le built-in,

hanno l'attributo __name__

class P(object): pass

P.__name__ # 'P'

int.__name__ # 'int'

P().__name__ # errore

P().__class__.__name__ # 'P'

Page 69: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

69

Attributi e metodi speciali

__dict__

E' un attributo molto importante che contiene un dizionario che associa i nomi degli attributi di un oggetto al loro valore. Tutti gli oggetti, comprese le built-in, hanno l'attributo __dict__.

aggiungere/rimuovere un attributo da un oggetto è equivalente ad aggiungere/rimuovere un elemento dal dizionario __dict__.

__dict__ non contiene le property!

Page 70: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

70

Attributi e metodi speciali

Esempio:

class P(object):

def __init__(self):

self.x=10

p = P()

p.__dict__ # {'x': 10}

p.__dict__['y'] = 20

p.y # 20

del p.__dict__['y']

Page 71: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

71

Attributi e metodi speciali

__slots__

E' possibile limitare il nome degli attributi a quelli presenti nell'attributo di classe __slots__.Migliora l'efficienza.Non è ereditabile

class P(object):

__slots__ = 'a', 'b'

p = P()

p.x = 10 # errore

Page 72: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

72

Metodo per chiamata a funzione

__call__(self,...)

E' un metodo di istanza che corrisponde all'operatore di chiamata a funzione ().

Permette di creare “oggetti funzione” come in C++Tutte le funzioni hanno __call__ (chiamata)

Tutte le classi hanno __call__ (costruttore)

Gli altri oggetti possono avere __call__ se lo definisco in maniera esplicita.

Page 73: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

73

Metodo per chiamata a funzione

Gli oggetti funzione sono più flessibili delle funzioni normali perché possono avere uno stato interno.

class Retta(object):

def __init__(self,P):

self.P = P

def __call__(self,x):

return self.P * x

retta = Retta(10) # oggetto funzione

print retta(1.2)

Page 74: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

74

Metodo per chiamata a funzione

In alternativa posso aggiungere dinamicamente attributi ad una funzione normale in quanto è a tutti gli effetti un oggetto:

def retta(x):

return retta.P * x

retta.P = 2

print retta(10) # 20

Ovviamente il primo approccio è più generale!

Page 75: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

75

Metodi per la rappresentazione

__str__

Serve per costruire una rappresentazione “concisa” dell'oggetto

E' utilizzata quando l'oggetto è stampato con print o convertito in stringa con str.

__repr__

Serve a costruire una rappresentazione “completa” dell'oggetto.

La stringa generata “dovrebbe” permettere di ricostruire completamente l'oggetto.

Page 76: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

76

Metodi per i contenitori

Esistono alcuni metodi utili per definire il comportamento di classi “contenitore”__len__: chiamata dalla funzione len.

__contains__: operatore in.

__iter__: comportamento come iteratore (for)

__getitem__: accesso in lettura ad un elemento

__setitem__: accesso in scrittura ad un elemento

__delitem__: cancellazione di un elemento

Tutti contenitori built-in (str, list, dict) hanno questi metodi già definiti.

Page 77: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

77

Metodi per I contenitori

__len__( self) Implementa la funzione built-in len(). Dovrebbe restituire la lunghezza dell'oggetto, un numero intero >= 0.

__getitem__( self, key) Implementa la valutazione di self[key]. Per i tipi sequenza, le chiavi accettate dovrebbero essere numeri interi ed oggetti slice.

Page 78: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

78

Metodi per I contenitori

__setitem__( self, key, value) implementa l'assegnamento a self[key].

__delitem__( self, key) implementa l'eliminazione di self[key]

__iter__( self) Restituisce un oggetto iteratore che può iterare su tutti gli oggetti nel contenitore.

Page 79: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

79

Metodi per i contenitori

__getitem__(self, key)__setitem__(self, key, value)__delitem__(self, key)

Queste funzioni servono per leggere, scrivere e cancellare un elemento del contenitore.

L'elemento viene identificato tramite una chiave key.

La chiave può essere per esempio un indice (liste), un valore (dizionari), un oggetto slice

Page 80: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

80

Metodi per i contenitori

L = [1,2,3]

L.__getitem__(1) # L[1]

L.__setitem__(0,'a') # L[0]='a'

L.__getitem__(slice(1,2)) # L[1:2]

D = {'a': 0, 'b': 2}

D.__delitem__('a') # del D['a']

Page 81: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

81

Metodi per i contenitori

slice E' una classe built-in si usa per rappresentare in maniera

compatta delle sequenze di indici.slice(start,end,step) rappresenta tutti gli indici che

partono da start e terminano in end-1 con passo step.

Le classi str e list hanno già implementato il meccanismo di slicing.

Quando viene creato un nuovo contenitore posso ridefinire il comportamento dello slicing.

Page 82: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

82

Metodi per i contenitori

Vediamo alcuni esempi:Lista circolareSetContatore di caratteriComposizione di funzioni

Page 83: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

83

Metodi per l'accesso agli attributi

Nella maggior parte dei casi l'accesso agli attributi di un'istanza può essere gestito con le property.

Il Python presenta un ulteriore meccanismo molto più flessibile per l'accesso agli attributi che consiste nel definire alcuni metodi speciali:__getattr____setattr____delattr__

Page 84: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

84

Metodi per l'accesso agli attributi

__getattr__(self,name)

Viene chiamato quando si accede all'attributo di nome name e questo non viene trovato in self.

__setattr__(self,name,value)

Viene chiamato quando si cerca di settare l'attributo di nome name con un valore value.

__delattr__(self,name)

Viene chiamato quando si cerca di eliminare l'attributo di nome name.

Page 85: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

85

Metodi per l'accesso agli attributi

p.x chiama p.__getattr__('x')

p.x = 100 chiama p.__setattr__('x',100)

del p.x chiama p.__delattr__('x')

Nota: quando si ridefiniscono questi metodi bisogna sempre fare riferimento all'attributo __dict__ in modo da evitare chiamate ricorsive.

Page 86: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

86

Metodi per la comparazione

Ci sono diversi metodi che implementano gli operatori matematici di comparazione__eq__ ==__ne__ !=__ge__ >=__gt__ >__le__ <=__lt__ <__cmp__ comparazione per differenza

Page 87: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

87

Metodi per la comparazione

__eq__ e __ne__

Ogni oggetto ha un id univoco durante l'esecuzione del programma (solitamente l'indirizzo di memoria)

Normalmente gli operatori == e != controllano se due variabili sono uguali/differennti per id cioè se si riferiscono o meno allo stesso oggetto

Se riscrivo questi metodi posso effettuare un controllo sul valore anziché sull'id

Page 88: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

88

Metodi per la comparazione

class P(object): pass class Persona(object): def __init__(self,n): self.nome=n def __eq__(self,other): return self.nome==other.nome

p1,p2 = P(),P() print p1==p2 # diversi p1,p2=Persona('Ale'),Persona('Ale') print p1==p2 # uguali

Page 89: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

89

Metodi per i tipi numerici

Ci sono infine diversi metodi che implementano gli operatori matematici più comuni

__add__ +

__sub__ -

__mul__ *

__div__ /

__pow__ **

...

Page 90: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

90

Metodi per i tipi numerici

Operatori “aumentati”

__iadd__ +=

__isub__ -=

__imul__ *=

__idiv__ /=

__ipow__ **=

...

Page 91: Programmazione Orientata agli Oggetti e Scripting in Python...Programmazione Orientata agli Oggetti e Scripting in Python Paradigma ad Oggetti - 1 DIEE Univ. di Cagliari DIEE - Università

91

Metodi per i tipi numerici

In tutto sono circa 50:

Operatori booleani

Operatori di shift

Operatori di conversione

...

(Vedere il manuale di riferimento)