2. Variabili di Classe e Variabili di Istanza
In questa lezione spiegheremo la differenza tra variabili di istanza e variabili di classe, tramite degli esempi che vi permetteranno di capire cosa sono queste variabili e quando sia conveniente usare un tipo rispetto all'altro. Questo vi permetterà di ottenere una visuale più approfondita e coerente del concetto di classe, che nel video precedente abbiamo definito come la "fabbrica di oggetti".
Variabili di istanza
Nella lezione precedente abbiamo creato una semplice classe Studente. Ciascuna istanza di questa classe, quindi ciascuno studente creato a partire da questo modello generico, dispone di attributi che sono propri di sé stesso, come il suo nome, il suo cognome e il suo corso_di_studi. Questi vengono chiamati variabili di istanza, come ricorderete vengono impostati tramite self, che rappresenta proprio una referenza a ciascuna istanza.
class Studente:
def __init__(self, nome, cognome, corso_di_studi):
self.nome = nome
self.cognome = cognome
self.corso_di_studi = corso_di_studi
def scheda_personale(self):
return f"Scheda Studente\n Nome:{self.nome}\n Cognome:{self.cognome}\n Corso Di Studi:{self.corso_di_studi}"
studente_uno = Studente("Py", "Mike", "programmazione")
studente_due = Studente("Marta", "Stannis", "scienze politiche")
Variabili di classe
Le variabili di classe invece sono attributi che vengono condivisi da tutte le istanze della classe.
Ad esempio, una caratteristica comune a tutti gli studenti di un'Istituto potrebbe essere il numero di ore di lezione settimanali. Potrebbe essere quindi una buona idea quella di definire una variabile di classe chiamata ore_settimanali, in modo che tutte le istanze abbiano questa proprietà senza bisogno di specificarla ogni volta.
Definire una variabile di classe è molto semplice:
class Studente:
ore_settimanali = 36 # Variabile Di Classe
def __init__(self, nome, cognome, corso_di_studi):
self.nome = nome
self.cognome = cognome
self.corso_di_studi = corso_di_studi
def scheda_personale(self):
return f"Scheda Studente\n Nome:{self.nome}\n Cognome:{self.cognome}\n Corso Di Studi:{self.corso_di_studi}"
Ora, volendo visualizzare il numero di ore settimanali nella scheda_personale, possiamo accedervi in due modi, tramite la classe o tramite l'istanza.
Come accedere alle variabili di classe tramite la classe
class Studente:
ore_settimanali = 36
# ...
def scheda_personale(self):
return f"Scheda Studente\n Nome:{self.nome}\n Cognome:{self.cognome}\n Corso Di Studi:{self.corso_di_studi}\n Ore Settimanali:{Studente.ore_settimanali}" # <---QUI
Come accedere alla variabile di classe tramite l'istanza
class Studente:
ore_settimanali = 36
# ...
def scheda_personale(self):
return f"Scheda Studente\n Nome:{self.nome}\n Cognome:{self.cognome}\n Corso Di Studi:{self.corso_di_studi}\n Ore Settimanali:{self.ore_settimanali}" # <---QUI
Forse vi starete chiedendo: ma se si tratta di variabili di classe, come mai è possibile accedervi anche tramite l'istanza? È semplice: succede che, quando proviamo ad accedere all'attributo di un'oggetto, Python controlla anzitutto se l'istanza contiene quell'attributo, e se non è presente allora va a cercarlo come variabile di Classe. Facile no? Ciascuno dei metodi di accesso è preferibile a seconda del caso specifico che state modellando: nel nostro esempio delle ore settimanali potrebbe essere preferibile utilizzare un accesso tramite self, spiegheremo ora il perché.
Supponiamo che studente_uno decida di frequentare anche un corso serale di 4 ore aggiuntive settimanali, e che il sistema debba quindi incrementare il numero delle ore settimanali della sua specifica scheda personale. Accedere alla varibile di classe tramite l'istanza si dimostra in questo caso una mossa vincente, possiamo infatti fare:
studente_uno.ore_settimanali += 4
print(studente_uno.scheda_personale())
print(studente_due.scheda_personale())
Scheda Studente
Nome:Py
Cognome:Mike
Corso Di Studi:programmazione
Ore Settimanali:40
Scheda Studente
Nome:Marta
Cognome:Stannis
Corso Di Studi:scienze politiche
Ore Settimanali:36
Così facendo, la nostra istanza si crea la sua versione personalizzata della variabile, senza influenzare gli oggetti restanti. Lasciate che ve lo dimostri visivamente:
print(Studente.__dict__)
print(studente_uno.__dict__)
{'__module__': '__main__', 'ore_settimanali': 36, '__init__': , 'scheda_personale': , '__dict__': , '__weakref__': , '__doc__': None}
{'nome': 'Py', 'cognome': 'Mike', 'corso_di_studi': 'programmazione'}
Come potete vedere, nella classe Studente è presente la variabile di classe ore_settimanali corrispondente a 36, mentre non è presente nell'istanza studente_uno.
Proviamo ora a ripetere il procedimento precedente, aggiungendo nuovamente 4 ore:
studente_uno.ore_settimanali += 4
{'__module__': '__main__', 'ore_settimanali': 36, '__init__': , 'scheda_personale': , '__dict__': , '__weakref__': , '__doc__': None}
{'nome': 'Py', 'cognome': 'Mike', 'corso_di_studi': 'programmazione', 'ore_settimanali': 40}
Ecco che ora abbiamo una variabile ore_settimanali anche in studente_uno, a cui è associato stavolta un 40.
Un altro esempio di variabile di classe
Facciamo ora un altro esempio di variabile di classe: vogliamo una variabile che rappresenti il numero totale di studenti dell'istituto. La mossa più saggia da fare in questo caso è quello di accedere alla variabile tramite la classe stessa, e faremo questo dal metodo __init__, in modo da incrementare il valore della variabile di classe ogni volta che uno studente viene inizializzato.
class Studente:
ore_settimanali = 36
corpo_studentesco = 0
def __init__(self, nome, cognome, corso_di_studi):
self.nome = nome
self.cognome = cognome
self.corso_di_studi = corso_di_studi
Studente.corpo_studentesco += 1
def scheda_personale(self):
return f"Scheda Studente\n Nome:{self.nome}\n Cognome:{self.cognome}\n Corso Di Studi:{self.corso_di_studi}\n Ore Settimanali:{self.ore_settimanali}"
studente_uno = Studente("Py", "Mike", "programmazione")
studente_due = Studente("Marta", "Stannis", "scienze politiche")
print(Studente.corpo_studentesco)
2
Ci viene restituito 2 perché la variabile di casse corpo_studentesco è stata incrementata due volte durante la creazione dei due oggetti studente_uno e studente_due.