-
Notifications
You must be signed in to change notification settings - Fork 0
/
object_oriented.py
271 lines (211 loc) · 7.53 KB
/
object_oriented.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#==============================================
# Esempio di classe con attributo e sottoclassi
#============================ ==================
class LoudTalker(object):
# qui aggiungo un attributo della classe di nome "suffix"
# l'attributo può essere referenziato attraverso:
# -l'oggetto della classe (LoudTalker.suffix)
# -l'istanza della classe (self.suffix)
suffix = "!"
def say(self, message):
print("%s%s" % (message, self.suffix))
class SubLoudTalker(LoudTalker):
pass
assert SubLoudTalker.suffix == "!"
class UnsureTalker(LoudTalker):
suffix = "..." # fa l'ovverride dell'attributo di LoudTalker ad un nuovo valore
pensively = UnsureTalker()
pensively.say("I'm pretty sure")
# e' possibile l'ereditarietà multipla
class Base1:
pass
class Base2:
pass
class MultiDerived(Base1, Base2):
pass
# e' possibile l'ereditarietà multilivello
class Base:
pass
class Derived1(Base):
pass
class Derived2(Derived1):
pass
#=============================================
# Esempio di classe base con inizializzazione
# e reimplementazione di metodi 'speciali'
#=============================================
class Array(object):
# il metodo __init__ è chiamato alla creazione dell'oggetto
# effettivamente questo metodo è un "inizializzatore"
# il metodo __new__ è il reale costruttore della classe
# ma di solito viene implementato ed usato solo nelle metaclassi
def __init__(self, length = 0, baseIndex = 0):
assert length >= 0
self._data = [ None for i in range(length) ] #crea una lista di elementi tutti a None
self._baseIndex = baseIndex # limite inferiore per gli indici
# implementa metodo __copy__ nel caso si usi la funzione python 'copy()'
# per copiare un oggetto di tipo Array
def __copy__(self):
result = Array(len(self._data))
for i, datum in enumerate(self._data):
result._data[i] = datum
result._baseIndex = self._baseIndex
return result
# ...
def getOffset(self, index):
offset = index - self._baseIndex
if offset < 0 or offset >= len(self._data):
raise IndexError
return offset
def __getitem__(self, index):
return self._data[self.getOffset(index)]
def __setitem__(self, index, value):
self._data[self.getOffset(index)] = value
#=============================================
# Esempio di classe astratta (solo python 3)
#=============================================
import abc
"""Una classe astratta può contenere uno o più metodi astratti,
Può essere usata come classe base per una derivata.
Non può essere istanziata.
si può fornire comunque nelle classi astratte una implementazione dei metodi,
che le sottoclassi possono utilizzare con super().
I metodi astratti devono essere implementati dalle classi 'concrete' derivate
Questa classe astratta estende la classe __builtin__.object """
class AbstractTalker(object):
__metaclass__ = abc.ABCMeta
def __init__(self):
""" permette polimorfismo
in questo caso possiamo riferirci alla classe Parent senza conoscere il suo nome
possiamo risalire così la gerarchia delle classi e chiamare i metodi delle classi parent """
super(AbstractTalker, self).__init__() # permette di riferirsi all'oggetto/istanza parent ed
# usare il suo metodo __init__()
# avrei potuto scrivere:
# object.__init__(self)
""" controlla la gerarchia degli oggetti/classi
posso usare anche il metodo "issubclass() """
def compara(self, obj):
if isinstance(self, obj.__class__): # controlla se 'self' è istanza della classe di obj
pass
elif isinstance(obj, self.__class__): # controlla se 'obj' è istanza della classe di self
pass
else:
return (self.__class__.__name__ == obj.__class__.__name__)
@abc.abstractmethod
def format(self, message):
return message # oppure: raise NotImplementedError
def say(self, message):
print(self.format(message))
# defininiamo in queste classi derivate l'implementazione dei metodi
class LoudTalker(AbstractTalker):
def format(self, message):
return "%s!" % message
class Screamer(LoudTalker):
def format(self, message):
return super(Screamer, self).format(message).upper()
# esempio di ereditarietà multipla, con classe astratta
class ShoutFormatterMixin(object):
def format(self, message):
return "%s!" % message
class PublicAddressSystem(ShoutFormatterMixin, AbstractTalker):
def play_music(self, song):
super(PublicAddressSystem, self).say(song.tablature)
#=============================================
# Esempio di namespace delle variabili
#=============================================
def outer_function():
a = 20
def inner_function():
a = 30
print('a =', a)
inner_function()
print('a =', a)
a = 10
outer_function()
print('a =', a)
## stampa:
# a = 30
# a = 20
# a = 10
def outer_function():
global a
a = 20
def inner_function():
global a
a = 30
print('a =', a)
inner_function()
print('a =', a)
a = 10
outer_function()
print('a =', a)
## stampa:
# a = 30
# a = 30
# a = 30
#=============================================
# Overloading di operatore __add__
#=============================================
class Point:
def __init__(self,x = 0,y = 0):
self.x = x
self.y = y
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y)
p1 = Point(2,3)
p2 = Point(-1,2)
print(p1 + p2)
# stampa (1,5)
#=============================================
# PROPRIETÀ
#=============================================
# Proprietà:
# sono un modo comodo ed elegante per esporre attributi della classe
"""
property() è una funzione builtin che ritorna un oggetto di tipo property
ha la seguente signature:
property(fget=None, fset=None, fdel=None, doc=None)
- un esempio:
temperature = property(get_temperature,set_temperature)
- altro esempio con funzioni lambda:
data = property(
fget = lambda self: self.getData())
baseIndex = property(
fget = lambda self: self.getBaseIndex(),
fset = lambda self, value: self.setBaseIndex(value))
"""
# si possono definire proprietà in sola lettura
# si possono definire proprietà in lettura/struttura
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(self):
print("Getting value")
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self._temperature = value
temperature = property(get_temperature,set_temperature)
# un secondo modo di definire le proprietà della classe
# è usare il decoratore @property e setter in questo modo
class Celsius:
def __init__(self, temperature = 0):
self._temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self._temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self._temperature = value