In questo articolo dedicato alle classi, metteremo insieme alcuni concetti visti finora (i tipi di dati, la sintassi e le funzioni ) per imparare a creare nuove classi in Python.
Le classi e le istanze
Questa volta partiamo subito con un esempio:
Ecco fatto! Abbiamo definito la nostra prima classe. Troppo facile, vero?
L’unica novità è l’istruzione class, mentre l’istruzione pass è lì solo perché dobbiamo per forza scrivere qualcosa nel corpo della definizione della nostra classe.
Ora proviamo a creare un’istanza della nostra classe:
Basta scrivere il nome della classe seguito dalla coppia di parentesi per far sì che Python ci fornisca un oggetto di quella classe, chiamato anche istanza della classe.
Ora, se proviamo a digitare Cibo e poi pasta, otteniamo questi due risultati:
I valori possono naturalmente essere differenti: indicano la posizione in memoria in cui sono collocati gli oggetti visualizzati.
- Nel caso di Cibo la parola class, presente della stringa visualizzata in output, indica che siamo in presenza di una classe.
- Nel secondo caso invece, pasta, la stringa indica:
– sia il fatto che si tratta di un oggetto e quindi object;
– sia la classe che ne ha permesso la creazione, ovvero __main__.Cibo.
Il nome speciale __main__ indica che la classe Cibo è stata definita interattivamente.
Se invece fosse stata definita e impostata da un modulo esterno, al posto di __main__ vedremmo il nome del modulo in questione.
I metodi
Adesso che sappiamo come definire classi in Python e come creare un oggetto appartenente ad una classe, cosa possiamo fare?
Cominciamo ad applicare quanto imparato nei precedenti articoli.
Vediamo una versione un po’ più evoluta della nostra classe Cibo:
La prima stringa che abbiamo aggiunto, dovremmo ricordarcelo, è la stringa di documentazione.
Come sappiamo, viene automaticamente assegnata all’attributo __doc__ della classe e visualizzata da help.
Il metodo __init__ (attenzione: sono tue “_” consecutivi) può sembrare un po’ criptico: si tratta del metodo costruttore per le classi in Python.
Quando creiamo un’istanza di una classe, è normale voler specificare alcune caratteristiche speciali e proprie dell’oggetto che stiamo costruendo.
Per fare ciò, possiamo definire un metodo apposito dal nome prestabilito __init__ (il costruttore appunto) e passargli dei valori all’atto della creazione dell’oggetto.
- Il primo parametro del costruttore (e di tutti i metodi di una classe) è self, il quale permette di accedere all’oggetto creato, o, nel caso di __init__, che sta per essere creato.
Quando richiamiamo un metodo, non dobbiamo fare espressamente riferimento a self: ci pensa Python ad assegnarlo.
Il fatto che si chiami “self” è una pura convenzione, che, anche se siamo anticonformisti, ci conviene rispettare se teniamo alla leggibilità del nostro codice.
Vediamo ora all’opera il nostro nuovo costruttore:
L’oggetto pasta ora ha tre nuovi attributi e possiamo provare a visualizzarne uno:
Sarebbe interessante aggiungere un po’ di ‘intelligenza’ alla nostra classe Cibo per calcolare, per esempio, le calorie di un alimento.
Con Python possiamo farlo interattivamente, creando una funzione e assegnandola come metodo della classe:
Le parentesi che “inglobano” l’espressione restituita dalla funzione, sono NECESSARIE solo se spezziamo l’istruzione su più righe.
Con le parentesi Python non segnalerebbe un errore di sintassi dovuto alla presenza del segno “+” a fine riga.
In alternativa si potrebbe inserire anche un backslash “\” come ultimo carattere della riga che prosegue a capo.
Abbiamo assegnato a posteriori alla nostra classe Cibo il metodo calcolaCalorie e l’oggetto pasta che avevamo già creato lo ‘riceve’ automaticamente:
Non è sorprendente il nostro Python?
Un metodo è una funzione abbinata all’oggetto, mentre un attributo è un dato che lo caratterizza.
Uno dei pilastri della programmazione object oriented sta proprio nel fatto che un oggetto “fonde” insieme sia i dati, sia la logica che opera su di essi.
Questo aspetto è denominato “incapsulamento” in quanto “ingloba” in un’unica identità (ovvero nell’oggetto) due aspetti normalmente distinti:
i dati (sotto forma di attributi) e il codice che li gestisce (sotto forma di metodi).
Le classi e l’ereditarietà
Altro pilastro della programmazione object oriented è proprio l’ereditarietà, che possiamo utilizzare in modo estremamente semplice nelle nostre classi in Python.
Ecco la definizione:
“Una classe eredita il comportamento di un’altra classe (la cosiddetta base class) estendendola però con funzionalità proprie. “
Come al solito, ricorriamo a un esempio per capire meglio tale concetto.
Estendiamo la nostra classe Cibo:
La nuova classe Verdura è di tipo Cibo, ma con la particolarità che l’attributo grassi è sempre uguale a 0.
Creiamo un’istanza di questa nuova classe e proviamo ad usare un metodo della classe base:
Nella classe Verdura non c’è alcuna traccia del metodo calcolaCalorie.
Ma poiché tale metodo era definito nella classe base Cibo, lo possiamo usare tranquillamente anche nella classe derivata.
Nel costruttore abbiamo espressamente ripetuto le istruzioni di assegnamento degli attributi della classe base.
Potrebbe essere più comodo (e più semanticamente corretto ) richiamare il costruttore della classe base.
Vediamo quindi la classe Verdura modificata:
Osserviamo la sintassi usata per richiamare il metodo costruttore originale: abbiamo usato il nome della classe base seguito da __init__ passandogli il parametro self.
Possiamo così, se ci serve, riutilizzare il costruttore della classe originaria.
In questo caso abbiamo semplicemente ‘forzato’ a 0 uno dei parametri (ovvero grassi ) che nella classe base poteva invece essere passato esplicitamente.
Le proprietà nelle classi in Python
Ripensiamo un attimo alla funzione calcolaCalorie definita all’inizio dell’articolo nella classe Cibo.
Non sarebbe più comodo poterla usare come se fosse un attributo, senza usare le parentesi?
Ebbene con Python possiamo farlo usando la funzione property:
Adesso la nostra classe Cibo ha una proprietà calorie che, quando richiamata, provoca l’esecuzione della funzione che abbiamo indicato come primo parametro di property.
Le proprietà possono anche essere usate per definire funzioni che definiscono degli attributi oltre che restituirli.
Vediamo in che modo possiamo usarle nella nostra classe Verdura con l’attributo grassi:
Vediamo cosa succede se definiamo una verdura con questa classe:
In questo modo la nostra classe Verdura avrà sempre e comunque l’attributo grassi uguale a 0.
Esistono altri due parametri che possiamo usare con property:
– una funzione richiamata durante la cancellazione dell’attributo
– la documentazione per l’attributo (sì, esatto: sempre quella che viene visualizzata con help ).
Metodi privati
Anche per le classi in Python esiste il concetto di metodo o attributo privato, presente anche in altri linguaggi di programmazione come C++ e Java.
Un metodo o un attributo privato non può essere richiamato dall’esterno della classe cui appartiene.
Ma a differenza di altri linguaggi di programmazione, per ottenere questa ‘privacy’ non abbiamo a disposizione una parola chiave, ma solo una convenzione di denominazione (in inglese naming convention ).
Un metodo o un attributo privato deve iniziare (ma non terminare) con una sequenza di due caratteri underscore “_”.
Proviamo ora a creare una classe con un metodo privato:
Creiamo un’istanza e proviamo a usare il metodo privato della classe:
Come vediamo, Python non ha eseguito il metodo che avevamo definito, rispettando la convenzione che lo rende privato.
Proviamo ora ad eseguire dir sulla classe Archivio:
Il metodo __apri_file ha subito un’operazione che in inglese viene definita name mangling: espressione traducibile come “storpiatura” dei nomi.
Se per qualsiasi motivo poi volessimo ad ogni costo e a nostro rischio e pericolo accedere a un metodo che avevamo definito privato, lo possiamo fare:
Non è finita qui: per le classi in Python abbiamo ancora tante altre funzionalità, di cui parleremo nel prossimo articolo! Continua a seguirci e iscriviti alla nostra newsletter per rimanere aggiornato!
Qui trovi tutto ciò che occorre sapere per utilizzare questo fantastico linguaggio di programmazione: Guida alla programmazione con Python.
3 risposte