ePrometeusCorsoLinuxLinux
testi articoli
Testi Articoli  Download
Home | OpenSource | PhpNuke | Programming | SysAdm | 
CorsoJava è ora Video! Free for all!
Clicca Qui!
UNO SGUARDO AL PYTHON
Uno sguardo al Python
Primo impatto
Sequenze e dizionari
Controllo di flusso
Windows e Java
Classi e Oggetti
Istanze
Classi
Ereditarietà
Eccezioni
Esempio: Gestione Form
Conclusioni
L'Autore


<<< Classi >>>

Impariamo adesso a creare nuove classi. Nel caso più semplice possiamo dichiarare una classe vuota:

>>> class Void:
... pass
...
>>> x = Void()
>>> x
<__main__.Void instance at 85ff80>
>>> x.a
Traceback (innermost last)
AttributeError: a
>>> x.a=1
>>> y = Void()
>>> y.a=2
>>> print x.a,y.a
1 2

Utilizzando la keyword class abbiamo dichiarato una nuova classe, in questo chiamata Void. In una definizione di classe possono esserci comandi di qualsiasi genere, che vengono eseguiti durante la definizione della classe. I comandi per noi interessanti comunque sono quelli che dichiarano attributi, ovvero variabili e funzioni che diventano campi e metodi della classe. Gli altri comandi possono servire per esempio a definire dei metodi condizionalmente (per esempio in un modo sotto Windows e un altro sotto Unix) ma è meglio non abusare di queste possibilità.

Ad una classe non vengono assegnati una volta e per tutte tutti i suoi attributi, ma possono essere aggiunti anche dopo che l'istanza è stata creata. Infatti in genere gli attributi vengono aggiunti in fase di inizializzazione. Come si vede nel'esempio, dopo aver dichiarato la classe, utilizziamo la funzione costruttore, avente lo stesso nome della classe, per creare nuove istanze. Nell'esempio utilizzando Void come funzione abbiamo creato l'istanza. Ogni instanza è un namespace separato che inizialmente non contiene alcun attributo. La natura dinamica del Python ci consente di aggiungere, "al volo", nuovi attribuiti, nell'esempio a. Che le istanze siano namespace separati e indipendenti si vede anche dal fatto che creando due istanze, possiamo assegnare ad ogni istanza un valore diverso per l'attribuito a. Otteniamo, come ci si aspetta, due a separati e indipendenti per ogni istanza.

class List:
	def __init__(self, data, next=None):
		self.data=data
		self.next=next
		
	def append(self, data):
		curr = self
		while not curr.next is None:
			curr = curr.next
		curr.next = List(data)
		return self
		 
	def push(self, data):
		return List(data,self)
		

	def printall(self):
		while not self is None:
			print self.data
			self=self.next
Listato 1

Le classi divengono interessanti quando contengono campi e metodi. Nel Listato 1 possiamo vedere la dichiarazione di una classe List, contenuta nel file list.py, che andiamo subito ad utilizzare:

>>> import list

>>> x = list.List(2) >>> x.printall <method List.printall of List instance at 8654a0> >>> x.printall() 2 >>> x = x.push(1) >>> x.printall() 1 2 >>> x=x.append(3) >>> x.printall() 1 2 3

Come si vede, abbiamo definito una classe lista con tre metodi: append, push e printall. Esaminiamo ora in dettaglio il meccanismo della definizione della classe. Dichiarando una classe ci ritroviamo con una funzione costruttore che ha lo stesso nome della classe. In realtà questo costruttore crea soltanto l'oggetto istanza, ma non lo inizializza. Se occorre effettuare delle inizializzazioni supplementari (caso abbastanza frequente), si deve definire una funzione di inizializzazione che si deve chiamare __init__. L'uso dei doppi underscore all'inizio e alla fine è una convenzione Python usata ovunque sia necessario definire nomi che hanno un significato speciale, e non è limitata solo a questo caso. La __init__ viene chiamata automaticamente dopo che è stata creata l'istanza dell'oggetto.

Veniamo ora a quello che è un punto critico, ed è basilare per comprendere tutto il meccanismo della OOP in Python. Dovrebbe essere chiaro come funzionano in Python le funzioni (non c'è niente di speciale, a parte il fatto che sono solitamente contenute dentro dei moduli). Ora, nelle classi non ci sono funzioni ma metodi. In OOP, in generale i metodi sono funzioni speciali, in quanto conoscono l'oggetto a cui appartengono. In Java, C++ e altri linguaggi OOP l'accesso all'oggetto corrente è implicito e nascosto: il programmatore non se ne accorge. In Python invece l'oggetto corrente viene passato esplicitamente come primo parametro della chiamata del metodo. Confrontando l'ultimo esempio con il listato il meccanismo dovrebbe diventare abbastanza chiaro. Precisamente, scrivendo x = list.List(2) si costruisce un oggetto istanza, poi viene chiamato automaticamente __init__(self, data, next=None). Il primo parametro di __init__ è l'oggetto appena costruito, il secondo è il parametro fornito al costruttore (2). In questo esempio si utilizza anche la feature dei parametri di default: poiché non abbiamo specificato il terzo parametro questo assume il valore di default None. Il meccanismo è analogo quando invochiamo i metodi: chiamato x.printall() viene chiamata la funzione printall passando x come primo parametro. Per convenzione il primo parametro di un metodo viene chiamato self. Non c'è niente di speciale in questo nome ma non seguire questa convenzione può compromettere la leggibilità del vostro listato ad altri programmatori Python. Non ci sono modi per accedere direttamente ai campi di un oggetto: occorre usare sempre il prefisso self. Per quanto questa cosa possa apparire noiosa, in pratica questo migliora la leggibilità e evita ambiguità con le variabili locali.

ePrometeus s.r.l. - Web Software House & Open Source System Integrator
MILANO - SAN BENEDETTO DEL TRONTO(AP)
Contatti: info@eprometeus.com