Le classi in Python

Partiamo dal presupposto che il lettore conosca già un po’ di teoria della programmazione ad oggetti. In questo articolo vogliamo riassumere gli elementi pratici per realizzare una classe in Python.

Partiamo dal presupposto che il python, non essendo un linguaggio compilato, ha una sintassi per la gestione delle classi più poliedrica rispetto ai fratelli più blasonati C++ o Java o C#, solitamente preferiti come linguaggi per un approccio alla Programmazione Orientata agli Oggetti (OOP).

E già con questo mini esempio iniziale dovrebbe essere palese. Creiamo un file Studente.py con il seguente listato:

class Studente:
    nome= "Alfredo"

if __name__ == "__main__":
    s = Studente()
    print(s.nome)

Eseguiamo da terminale nella posizione di salvataggio con il comando python Studente.py o eseguiamolo da IDLE.

Possiamo già notare delle anomalie: nella classe non abbiamo creato un costruttore ma abbiamo inserito una variabile che funge da classico attributo, inizializzata per giunta nello stesso contesto senza una dicitura di pubblico o privato. Nel programma principale abbiamo creato una istanza e abbiamo stampato con accesso diretto il valore dell’attributo della classe. In questo modo è decisamente più veloce e semplice realizzare le classi, la sintassi è ridotta davvero all’osso.

Proviamo a rendere la nostre classi più simili agli standard OOP e aggiungiamo un metodo di stampa e un costruttore.

class Studente:
    def __init__(self, _nome, _cognome):
        self.nome = _nome
        self.cognome = _cognome
        self.annonascita = 1700

    def print(self):
        print("Nome: " + self.nome + "\n" + "Cognome: " + self.cognome + "\n" + "Anno di nascita: "+self.annonascita )

if __name__ == "__main__":
    s = Studente("Alfredo", "Centinaro")
    s.annonascita = 1982
    s.print()

Come possiamo vedere, abbiamo una similitudine tra il classico elemento this che qui in python diventa self. Si usa anche come primo parametro, o meglio una sorta di pseudo parametro nei metodi per permettere l’invocazione sull’istanza della classe stessa.

Il costruttore qui non ha il nome della classe, ma __init__ e prende i parametri che si vuole passare al costruttore per inizializzare l’oggetto. Perché utilizzare il costruttore se posso direttamente inizializzare le variabili? In realtà è una questione di praticità. Le variabili dentro l’__init__ assumo il valore specifico solo per l’istanza che chiama il costruttore. Le variabili fuori dall’__init__, vengono dette variabili di classe e hanno lo stesso valore per tutte le istanze a prescindere, un po’ come se fossero valori statici, almeno inizialmente. Non conviene usare variabili sparse se vogliamo essere puntigliosi del mondo OOP. Se all’interno dell’istanza modifico il valore della variabile di classe, questa modifica solo la singola istanza pero!

class Studente:

    annodicorso = 1

    def __init__(self, _nome, _cognome):
        self.nome = _nome
        self.cognome = _cognome
        self.annonascita = 1700
    def print(self):
        print("Nome: " + self.nome + "\n" + 
              "Cognome: " + self.cognome + "\n" + 
              "Anno di nascita: "+ str(self.annonascita) + "\n" +
              "Anno di corso: " + str(self.annodicorso) )

if __name__ == "__main__":
    s = Studente("Alfredo", "Centinaro")
    s.annonascita = 1982
    s.print()

    z = Studente("Pippo", "Franco")
    z.annonascita = 1973
    z.annodicorso = 2
    z.print()    

Se lanciamo il codice di questa versione di classe otteniamo:

Nome: Alfredo
Cognome: Centinaro
Anno di nascita: 1982
Anno di corso: 1
Nome: Pippo
Cognome: Franco
Anno di nascita: 1973
Anno di corso: 2

Continua però a non esserci un sistema di protezione ed incapsulamento: possiamo alterare il nostro oggetto in modo diretto anche senza specificare un metodo di accesso o modifica, che diventano quindi quasi inutili. L’evidenza qui è nell’attributo annonascita che viene modificato direttamente prima della stampa.

Vedremo nelle prossime lezioni scope, namespace ed ereditarietà.

Ultima modifica 26 Agosto 2022