Abbiamo già considerato la parte funzionale di classi ed oggetti; rimane da vedere come gestire la parte dei dati. In realtà sono delle normali variabili accoppiate allo spazio dei nomi di classi ed oggetti, cioè hanno validità solo all'interno del contesto di queste classi o oggetti.
Ci sono due tipi di campi: variabili delle classi e variabili degli oggetti; esse vengono classificate in un modo o l'altro a seconda della loro appartenenza ad una classe o ad un oggetto rispettivamente.
Le variabili della classe sono condivise nel senso che sono accessibili da tutti gli oggetti (istanze) della classe. Esiste solo una copia della variabile della classe, e quando un oggetto ne modifica il contenuto, il cambiamento si riflette anche su tutte le altre istanze della classe.
Le variabili degli oggetti sono proprietà di ogni singolo oggetto/istanza della classe. In questo caso ogni oggetto ha la propria copia del campo e le variabili non sono condivise né collegate in alcun modo ad altre variabili con lo stesso nome in istanze differenti della stessa classe. Un esempio può chiarire questo punto.
Esempio 11.4. Uso delle variabili di classi e oggetti
#!/usr/bin/python # Filename: objvar.py class Person: '''Represents a person.''' population = 0 def __init__(self, name): '''Initializes the person's data.''' self.name = name print '(Initializing %s)' % self.name # Quando questa persona viene creata # lui/lei incrementa la popolazione # di una unita' Person.population += 1 def __del__(self): '''I am dying.''' print '%s says bye.' % self.name Person.population -= 1 if Person.population == 0: print 'I am the last one.' else: print 'There are still %d people left.' % Person.population def sayHi(self): '''Greeting by the person. Really, that's all it does.''' print 'Hi, my name is %s.' % self.name def howMany(self): '''Prints the current population.''' if Person.population == 1: print 'I am the only person here.' else: print 'We have %d persons here.' % Person.population swaroop = Person('Swaroop') swaroop.sayHi() swaroop.howMany() kalam = Person('Abdul Kalam') kalam.sayHi() kalam.howMany() swaroop.sayHi() swaroop.howMany()
$ python objvar.py (Initializing Swaroop) Hi, my name is Swaroop. I am the only person here. (Initializing Abdul Kalam) Hi, my name is Abdul Kalam. We have 2 persons here. Hi, my name is Swaroop. We have 2 persons here. Abdul Kalam says bye. There are still 1 people left. Swaroop says bye. I am the last one.
Questo esempio è un po' più lungo degli altri ma permette
di dimostrare la natura delle variabili di classi ed oggetti.
Nell'esempio population deriva dalla classe
Person e quindi è una variabile di classe.
La variabile name deriva dall'oggetto
(viene assegnata usando self) e perciò è una
variabile oggetto.
Pertanto ci riferiamo alla variabile di classe population
come Person.population e non come
self.population. Si noti che una variabile oggetto con lo
stesso nome di una variabile di classe occulterà la variabile di classe!
Si fa riferimento alla variabile oggetto name usando
la notazione self.name nel metodo di questo oggetto.
Ci si ricordi di questa semplice differenza tra variabili di classe e
oggetto.
Si osservi che il metodo __init__ viene usato per
inizializzare l'istanza Person con un nome. In questo
metodo, il contatore population viene incrementato di 1
dato che si è aggiunta una persona. Si osservi ancora che il valore di
self.name è specifico per ogni oggetto, ad indicare la
natura variabile degli oggetti.
Ricordarsi che ci si deve riferire a variabili e metodi dello stesso
oggetto usando solo la variabile
self. Questo viene chiamato un riferimento ad
attributo.
In questo programma si vede anche l'uso delle
docstring per le classi così come per i
metodi. Si può accedere alle docstring della classe al runtime usando
Person.__doc__ e alla docstring del metodo con
Person.sayHi.__doc__.
Esiste un altro metodo speciale come il metodo __init__;
si tratta di __del__ che viene chiamato quando un
oggetto sta per terminare la sua esistenza, non verrà più usato e quindi
il sistema può riutilizzare quella porzione di memoria che prima lo riguardava.
In questo metodo viene semplicemente decrementato il contatore
Person.population di 1 unità .
Il metodo __del__ viene eseguito quando l'oggetto
non è più in uso e non si prevede di riutilizzarlo. Per far questo,
si ricorre all'istruzione del come è stata usata nel
precedente esempio.
Generalmente parlando in Python tutti i membri di una classe (inclusi i dati) sono pubblici e tutti i metodi sono virtuali.
Unica eccezione: se si usano dati con nomi che usano come prefisso il simbolo di
doppia sottolineatura come __privatevar,
Python usa questa nomenclatura per creare variabili private.
La convenzione seguita è che il nome di ogni variabile che viene usata esclusivamente all'interno di una classe od oggetto, dovrebbe iniziare con un carattere di sottolineatura, e tutti gli altri nomi pubblici possono venire usati anche da altre classi/oggetti. Ma questa è solo una convenzione e non viene assolutamente imposta da Python (eccetto per il prefisso col carattere di doppia sottolineatura).
Si noti inoltre che il metodo __del__ è del tutto analogo
al concetto di un distruttore.