A Byte of Python

Variabili di classi e oggetti

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.

Uso delle variabili di classi e oggetti

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()
				
				

Output

				
$ 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.
				
				

Funzionamento

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.

Note per programmatori C++ / Java / C#

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.