12. Le classi e gli oggetti
La classe è lo stampo da cui vengono creati gli oggetti. Si dice che l’oggetto sia un’istanza di una classe.

Nota: la cartella [shared] è stata inserita nella cartella [Sources Root] del progetto.
12.1. script [classes_01]: una classe Oggetto
Lo script [classes_01] mostra un utilizzo obsoleto delle classi:
# una classe
class Objet(object):
"""une classe Objet vide"""
# ogni variabile di tipo [Objet] può avere attributi per definizione
obj1 = Objet()
obj1.attr1 = "un"
obj1.attr2 = 100
# visualizza l'oggetto
print(f"objet1=[{obj1}, {type(obj1)},{id(obj1)},{obj1.attr1},{obj1.attr2}]")
# modifica l'oggetto
obj1.attr2 += 100
# visualizza l'oggetto
print(f"objet1=[{obj1.attr1},{obj1.attr2}]")
# assegna il riferimento obj1 a obj2
obj2 = obj1
# modifica l'oggetto a cui punta obj2
obj2.attr2 = 0
# visualizza entrambi gli oggetti: obj1 ora punta a un oggetto modificato
print(f"objet1=[{obj1.attr1},{obj1.attr2}]")
print(f"objet2=[{obj2.attr1},{obj2.attr2}]")
# obj1 e obj2 puntano allo stesso oggetto
print(f"objet1=[{obj1}, {id(obj1)},{obj1.attr1},{obj1.attr2}]")
print(f"objet2=[{obj2}, {id(obj2)},{obj2.attr1},{obj2.attr2}]")
print(obj1 == obj2)
# tipo dell'istanza obj1
print(f"type(obj1)={type(obj1)}")
print(f"isinstance(obj1,Objet)={isinstance(obj1, Objet)}, isinstance(obj1,object)={isinstance(obj1, object)}")
# ogni tipo è un oggetto in Python
print(f"type(4)={type(4)}")
print(f"isinstance(4, int)={isinstance(4, int)}, isinstance(4, object)={isinstance(4, object)}")
Note:
- righe 2-3: una classe [Objet] vuota;
- riga 2: la classe può essere dichiarata in tre forme:
- class Oggetto;
- class Oggetto();
- class Oggetto(object);
- riga 3: un'altra forma di commento. Questo, preceduto da tre "", può estendersi su più righe;
- riga 7: istanziazione della classe Objet. Il risultato è un indirizzo, come mostreranno le righe 24-26;
- righe 8-9: inizializzazione diretta di due attributi dell'oggetto;
- riga 17: copia di riferimenti. Le variabili obj1 e obj2 sono due puntatori (riferimenti) allo stesso oggetto;
- riga 19: si modifica l’oggetto puntato da [obj2]. Poiché [obj1] e [obj2] puntano allo stesso oggetto, la visualizzazione degli oggetti [obj1, obj2] alle righe 21 e 22 mostrerà che l’oggetto puntato da [obj1] è cambiato;
- righe 24-26: queste righe hanno lo scopo di dimostrare l’uguaglianza delle variabili [obj1] e [obj2]. La visualizzazione della riga 26 lo dimostrerà. In questo confronto, sono gli indirizzi [obj1] e [obj2] ad essere uguali;
- ogni oggetto Python è identificato da un numero univoco che si ottiene con l'espressione [id(objet)]. Le righe 24 e 25 mostreranno che i numeri degli oggetti a cui puntano [obj1] e [obj2] sono identici, dimostrando così che questi due riferimenti puntano allo stesso oggetto;
- righe 27-29: la funzione [isinstance(expr,Type)] restituisce il valore booleano True se l’espressione [expr] è di tipo [Type]. In questo caso, vedremo che [obj1] è di tipo [Objet], il che sembra naturale, ma è anche di tipo [object]. La classe [object] è la classe padre di tutte le classi Python. Per proprietà dell’ereditarietà delle classi, una classe figlia F possiede tutte le proprietà della sua classe padre P e la funzione [isinstance(instance de F, P)] restituisce True;
- righe 30-32: mostrano che anche il tipo [int] è un tipo [object]. Tutti i tipi di Python derivano dalla classe [object];
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_01.py
objet1=[<__main__.Objet object at 0x0000025C3F469BB0>, <class '__main__.Objet'>,2595221838768,un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
objet1=[<__main__.Objet object at 0x0000025C3F469BB0>, 2595221838768,un,0]
objet2=[<__main__.Objet object at 0x0000025C3F469BB0>, 2595221838768,un,0]
True
type(obj1)=<class '__main__.Objet'>
isinstance(obj1,Objet)=True, isinstance(obj1,object)=True
type(4)=<class 'int'>
isinstance(4, int)=True, isinstance(4, object)=True
Process finished with exit code 0
12.2. Script [classes_02]: una classe Persona
Lo script [classes_02] mostra che gli attributi di una classe sono pubblici: sono accessibili direttamente dall’esterno della classe. Anche in questo caso si tratta di un utilizzo delle classi sconsigliato. Lo riportiamo comunque perché a volte è possibile imbattersi in questo tipo di codice (Python lo accetta) ed è quindi necessario essere in grado di comprenderlo.
# classe Persona
class Personne:
# attributi della classe
# non dichiarati - possono essere creati dinamicamente
# metodo
def identité(self: object) -> str:
# a priori, utilizza attributi inesistenti
return f"[{self.prénom},{self.nom},{self.âge}]"
# ---------------------------------- main
# gli attributi sono pubblici e possono essere creati dinamicamente
# istanziazione della classe
p = Personne()
# inizializzazione diretta degli attributi della classe
p.prénom = "Paul"
p.nom = "de la Hûche"
p.âge = 48
# chiamata di un metodo della classe
print(f"personne={p.identité()}")
# tipo dell'istanza p
print(f"type(p)={type(p)}")
print(f"isinstance(Personne)={isinstance(p, Personne)}, isinstance(object)={isinstance(p, object)}")
Note:
- righe 2-9: una classe con un metodo;
- riga 7: ogni metodo di una classe deve avere come primo parametro l’oggetto self, che indica l’oggetto corrente. Il metodo [identité] restituisce una stringa di caratteri;
- riga 15: istanziazione di un oggetto [Personne];
- righe 16-19: mostrano che gli attributi dell'oggetto possono essere creati dinamicamente (non esistono nella definizione della classe);
- riga 9: gli attributi della classe sono indicati con la notazione [self.attribut];
- le righe 23-24 mostreranno che l'oggetto [p] è al tempo stesso un'istanza della classe [Personne] e della classe [object];
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_02.py
personne=[Paul,de la Hûche,48]
type(p)=<class '__main__.Personne'>
isinstance(Personne)=True, isinstance(object)=True
Process finished with exit code 0
12.3. Script [classes_03]: la classe Personne con un costruttore
Lo script [classes_03] illustra l'utilizzo standard di una classe:
# classe Persona
class Personne:
# costruttore - inizializza tre attributi
def __init__(self: object, prénom: str, nom: str, âge: int):
# nome: nome della persona
# cognome: cognome della persona
# età: età della persona
self.prénom = prénom
self.nom = nom
self.âge = âge
# restituisce gli attributi della classe sotto forma di stringa di caratteri
def identité(self: object) -> str:
return f"[{self.prénom},{self.nom},{self.âge}]"
# ---------------------------------- mano
# un oggetto Persona
p = Personne("Paul", "de la Hûche", 48)
# chiamata di un metodo
print(f"personne={p.identité()}")
Note:
- riga 4: il costruttore di una classe si chiama __init__. Come per gli altri metodi, il suo primo parametro è self;
- riga 20: un oggetto Personne viene creato con il costruttore della classe;
- righe 13-15: il metodo [identité] restituisce una stringa di caratteri che rappresenta il contenuto dell'oggetto;
- riga 22: visualizzazione dell’identità della persona;
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_03.py
personne=[Paul,de la Hûche,48]
Process finished with exit code 0
12.4. Script [classes_04]: metodi statici
Nella cartella [modules] definiamo la seguente classe [Utils] (utils.py):

class Utils:
# metodo statico
@staticmethod
def is_string_ok(string: str) -> bool:
# string è una stringa
erreur = not isinstance(string, str)
if not erreur:
# la stringa è vuota?
erreur = string.strip() == ''
# risultato
return not erreur
Note
- riga 3: l'annotazione [@staticmethod] indica che il metodo così annotato è un metodo di classe e non un metodo di istanza. Ciò è evidente dal fatto che il primo parametro del metodo così annotato non è la parola chiave [self]. Pertanto, il metodo statico non ha accesso agli attributi dell’oggetto. Invece di scrivere:
si scrive
Poiché sopra abbiamo scritto [Utils.is_string_ok], il metodo [is_string_ok] è detto metodo di classe (in questo caso la classe Utils). Per questo motivo, il metodo [Utils.is_string_ok] deve essere annotato con la parola chiave [@staticmethod].
Il metodo statico [Utils.is_string_ok] consente in questo caso di verificare che un dato sia una stringa di caratteri non vuota.
Lo script [classes_04] utilizza la classe [Utils] nel modo seguente:
# si configura l'applicazione
import config
config = config.configure()
# il syspath è configurato - è possibile eseguire le importazioni
from utilitaires import Utils
print(Utils.is_string_ok(" "))
print(Utils.is_string_ok(47))
print(Utils.is_string_ok(" q "))
- righe 1-4: si utilizza uno script di configurazione;
Lo script di configurazione [config.py] è il seguente:
def configure():
import os
# cartella del file di configurazione
script_dir = os.path.dirname(os.path.abspath(__file__))
# percorsi assoluti delle cartelle da inserire nel syspath
absolute_dependencies = [
f"{script_dir}/shared",
"C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/venv/lib/site-packages",
"C:/myprograms/Python38/lib",
"C:/myprograms/Python38/DLLs"
]
# aggiornamento del syspath
from myutils import set_syspath
set_syspath(absolute_dependencies)
# si ripristina la configurazione
return {}
- riga 9: la cartella [shared] verrà inserita nel Python Path;
Il risultato dell'esecuzione è il seguente:
12.5. Script [classes_05]: controlli di validità degli attributi
Lo script [classes_05] introduce nuovi concetti:
- definizione di un tipo di eccezione proprietario;
- definizione del metodo [_str_], che è il metodo di identità predefinito delle classi;
- definizione delle proprietà;
# si configura l'applicazione
import config
config = config.configure()
# il syspath è configurato - è possibile eseguire le importazioni
from utilitaires import Utils
# una classe di eccezione proprietaria derivata da [BaseException]
class MyException(BaseException):
# non si esegue alcuna operazione: classe vuota
pass
# classe Persona
class Personne:
# costruttore
def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0):
# nome: nome della persona
# cognome: cognome della persona
# età: età della persona
# memorizzazione dei parametri
# le inizializzazioni verranno effettuate tramite i setter
self.prénom = prénom
self.nom = nom
self.âge = âge
# metodo toString della classe
def __str__(self: object) -> str:
return f"[{self.__prénom},{self.__nom},{self.__âge}]"
# getter
@property
def prénom(self) -> str:
return self.__prénom
@property
def nom(self) -> str:
return self.__nom
@property
def âge(self) -> int:
return self.__âge
# setter
@prénom.setter
def prénom(self, prénom: str):
# il nome deve essere diverso da vuoto
if Utils.is_string_ok(prénom):
self.__prénom = prénom.strip()
else:
raise MyException("Le prénom doit être une chaîne de caractères non vide")
@nom.setter
def nom(self, nom: str):
# il nome deve essere non vuoto
if Utils.is_string_ok(nom):
self.__nom = nom.strip()
else:
raise MyException("Le nom doit être une chaîne de caractères non vide")
@âge.setter
def âge(self, âge: int):
# l'età deve essere un numero intero >=0
erreur = False
if isinstance(âge, int):
if âge >= 0:
self.__âge = âge
else:
erreur = True
else:
erreur = True
# errore?
if erreur:
raise MyException("L'âge doit être un entier >=0")
# ---------------------------------- main
# un oggetto Persona
try:
# istanziazione della classe Persona
p = Personne("Paul", "de la Hûche", 48)
# visualizzazione dell'oggetto p
print(f"personne={p}")
except MyException as erreur:
# visualizzazione dell'errore
print(erreur)
# un altro oggetto Persona
try:
# istanza della classe Persona
p = Personne("xx", "yy", "zz")
# visualizzazione dell'oggetto p
print(f"personne={p}")
except MyException as erreur:
# visualizzazione errore
print(erreur)
# un'altra persona, questa volta senza parametri
try:
# istanza della classe Persona
p = Personne()
# visualizzazione dell'oggetto p
print(f"personne={p}")
except MyException as erreur:
# visualizzazione del messaggio di errore
print(erreur)
# non è possibile accedere agli attributi privati __attr della classe
p.__prénom = "Gaëlle"
print(f"p.prénom={p.prénom}")
print(f"p.__prénom={p.__prénom}")
p.prénom = "Sébastien"
print(f"p.prénom={p.prénom}")
print(f"p.__prénom={p.__prénom}")
Note:
- righe 10-13: una classe MyException derivata dalla classe BaseException (vedremo questo punto più avanti). Non aggiunge alcuna funzionalità a quest'ultima. È presente solo per avere un'eccezione proprietaria;
- riga 19: il costruttore ha valori predefiniti per i suoi parametri. Pertanto, l'operazione p=Personne() è equivalente a p=Personne("x","y",0);
- righe 34-45: le proprietà della classe. Si tratta di metodi annotati con la parola chiave [@property]. Sono utilizzati per restituire il valore degli attributi;
- righe 47-77: i setter della classe. Si tratta di metodi annotati con la parola chiave [@attributsetter]. Vengono utilizzati per impostare il valore degli attributi;
- righe 48-54: il setter dell'attributo [prénom]. Questo metodo verrà chiamato ogni volta che si assegnerà un valore all'attributo [prénom]:
La riga 2 provocherà la chiamata a [p.prénom(valeur)]. Il vantaggio di utilizzare un setter per assegnare un valore a un attributo è che, essendo il setter una funzione, è possibile verificare la validità del valore assegnato all’attributo;
- riga 51: si verifica che il valore assegnato all’attributo [prénom] sia una stringa non vuota. A tal fine si utilizza il metodo statico [Utils.isStringOk] visto in precedenza;
- riga 52: il valore assegnato all’attributo [prénom] viene privato degli spazi iniziali e finali della stringa e assegnato all’attributo [self.__prénom]. Non è quindi l’attributo [prénom] che viene utilizzato in questo caso. Non sarebbe stato possibile altrimenti, altrimenti si sarebbe verificata una chiamata ricorsiva infinita. Si sarebbe potuto utilizzare qualsiasi nome di attributo. Il fatto di aver utilizzato l’attributo [__prénom] con due trattini bassi all’inizio dell’identificatore ha un significato speciale: gli attributi preceduti da due trattini bassi sono privati della classe. Ciò significa che non sono visibili dall’esterno della stessa. Non è quindi possibile scrivere:
In realtà vedremo presto che è possibile scriverlo, ma ciò non modifica il nome. Ha un altro effetto;
- righe 53-54: se il valore assegnato al nome non è corretto, viene generata un’eccezione. In questo modo il codice chiamante saprà che la sua chiamata è errata;
- righe 35-37: la proprietà [prénom]. Verrà richiamata ogni volta che si scriverà [p.prénom] in un'espressione. A quel punto verrà richiamato il metodo [p.prénom()]. Riga 37: si restituisce il valore dell’attributo [__prénom], poiché abbiamo visto che il setter dell’attributo [prénom] assegnava il proprio valore all’attributo privato [__prénom];
- righe 56-62: il setter dell'attributo [nom] è costruito in modo analogo a quello dell'attributo [prénom]. Lo stesso vale per quello dell’attributo [âge] alle righe 64-77;
- sebbene le proprietà [prénom, nom, valeur] non siano i veri e propri attributi, che in realtà sono [__prénom, __nom, __âge], continueremo a chiamarle attributi della classe, poiché vengono utilizzate come tali;
- righe 19-28: il costruttore della classe utilizza implicitamente i setter degli attributi [prénom, nom, âge]. Infatti, scrivendo, alla riga 26, [self.prénom = prénom], verrà implicitamente chiamato il metodo [prénom(self, prénom)]. Verrà quindi verificata la validità del parametro [prénom]. Lo stesso vale per gli altri due attributi [nom, âge];
- con questo modello, non è possibile assegnare valori errati agli attributi [prénom, nom, âge] della classe;
- righe 30-32: la funzione __str__ sostituisce il metodo precedentemente denominato identité. Il nome [__str__] (con due trattini bassi all'inizio e alla fine) non è casuale. Lo vedremo in seguito;
- righe 83-86: istanziamento di una persona e successiva visualizzazione della sua identità;
- riga 84: istanziazione;
- riga 86: visualizzazione. L'operazione richiede di visualizzare la persona p sotto forma di stringa di caratteri. L’interprete Python chiama quindi automaticamente il metodo p.__str__(), se esiste. Questo metodo svolge la stessa funzione del metodo toString() in Java o nei linguaggi .NET;
- righe 87-89: gestione di un'eventuale eccezione di tipo MyException. Viene quindi visualizzato l'errore;
- righe 91-99: lo stesso vale per una seconda persona istanziata con parametri errati;
- righe 102-109: lo stesso vale per una terza istanza creata con i parametri predefiniti: non viene passato alcun parametro. In questo caso vengono utilizzati i valori predefiniti di tali parametri nel costruttore;
- righe 112-117: abbiamo detto che l'attributo [__prénom] era privato, quindi normalmente non accessibile dall'esterno della classe. Vogliamo verificarlo;
- righe 112-114: si assegna un valore all'attributo [__prénom], quindi si verifica il valore degli attributi [__prénom] e [prénom], che normalmente sono uguali;
- righe 115-117: si ripete l'operazione, questa volta inizializzando l'attributo [prénom];
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_05.py
personne=[Paul,de la Hûche,48]
L'âge doit être un entier >=0
personne=[x,y,0]
p.prénom=x
p.__prénom=Gaëlle
p.prénom=Sébastien
p.__prénom=Gaëlle
Process finished with exit code 0
Note
- righe 5-6: si nota che l'assegnazione [p.__prénom = "Gaëlle"] non ha modificato il valore dell'attributo [prénom], riga 5;
- righe 7-8: si nota che l'assegnazione [p.prénom = "Sébastien"] non ha modificato il valore dell'attributo [__prénom], riga 8;
Cosa si può dedurre da ciò? Probabilmente, l’operazione [p.__prénom = "Gaëlle"] ha creato un attributo pubblico [__prénom] nella classe, ma questo è diverso dall’attributo privato [__prénom] manipolato al suo interno;
12.6. Script [classes_06]: aggiunta di un metodo di inizializzazione dell’oggetto
Lo script [classes_06] aggiunge un metodo alla classe [Personne]:
# si configura l'applicazione
import config
config = config.configure()
# il syspath è configurato - è possibile eseguire le importazioni
from utilitaires import Utils
# una classe proprietaria di eccezione derivata da [BaseException]
class MyException(BaseException):
# non si fa nulla: classe vuota
pass
# classe Persona
class Personne:
# costruttore
def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0):
# nome: nome della persona
# cognome: cognome della persona
# età: età della persona
# memorizzazione dei parametri
# le inizializzazioni verranno effettuate tramite i setter
self.prénom = prénom
self.nom = nom
self.âge = âge
# altro metodo di inizializzazione
def init_with_personne(self: object, p: object):
# inizializza l'oggetto corrente con una persona p
self.__init__(p.prénom, p.nom, p.âge)
# metodo toString della classe
def __str__(self: object) -> str:
return f"[{self.__prénom},{self.__nom},{self.__âge}]"
# getter
…
# setter
…
# ---------------------------------- main
# un oggetto Persona
try:
# istanziazione della classe Persona
p = Personne("Paul", "de la Hûche", 48)
# visualizzazione dell'oggetto p
print(f"personne={p}")
except MyException as erreur:
# visualizzazione del messaggio di errore
print(erreur)
# un altro oggetto Persona
try:
# istanza della classe Persona
p = Personne("xx", "yy", "zz")
# visualizzazione oggetto p
print(f"p={p}")
except MyException as erreur:
# visualizzazione del messaggio di errore
print(erreur)
# un'altra persona, questa volta senza parametri
try:
# istanza della classe Persona
p = Personne()
# visualizzazione dell'oggetto p
print(f"p={p}")
except MyException as erreur:
# visualizzazione del messaggio di errore
print(erreur)
# un'altra Persona ottenuta tramite copia
try:
# istanza della classe Persona
p2 = Personne()
p2.init_with_personne(p)
# visualizzazione dell'oggetto p2
print(f"p2={p2}")
except MyException as erreur:
# visualizzazione messaggio di errore
print(erreur)
Note:
- la differenza rispetto allo script precedente si trova alle righe 30-33. È stato aggiunto il metodo initWithPersonne, che richiama il costruttore __init__. Non è possibile, come nei linguaggi tipizzati, avere metodi con lo stesso nome differenziati in base alla natura dei loro parametri o del loro risultato. Non è quindi possibile avere più costruttori che creino l’oggetto a partire da parametri diversi, in questo caso un oggetto di tipo Personne;
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_06.py
personne=[Paul,de la Hûche,48]
L'âge doit être un entier >=0
p=[x,y,0]
p2=[x,y,0]
Process finished with exit code 0
12.7. Script [classes_07]: un elenco di oggetti Persona
Ora inseriamo le classi [MyException] e [Personne] in un modulo per poterle utilizzare senza dover ricopiare il loro codice:

Entrambe le classi saranno contenute nel modulo [myclasses.py] sopra indicato.
Lo script [classes_07] mostra come ottenere un elenco di oggetti:
# si configura l'applicazione
import config
config = config.configure()
# il syspath è configurato - è possibile eseguire le importazioni
from myclasses import Personne
# ---------------------------------- main
# creazione di un elenco di oggetti "persona"
groupe = [Personne("Paul", "Langevin", 48), Personne("Sylvie", "Lefur", 70)]
# identità di queste persone
for i in range(len(groupe)):
print(f"groupe[{i}]={groupe[i]}")
Note:
- riga 7: si importa la classe [Personne];
- riga 11: un elenco di oggetti di tipo [Personne];
- righe 13-14: si percorre questa lista per visualizzare ciascuno dei suoi elementi;
- riga 14: la funzione [print] visualizzerà la stringa che rappresenta l'oggetto [groupe[i]]. Per impostazione predefinita, verrà chiamato il metodo [__str__];
Risultati
C:\Users\serge\.virtualenvs\cours-python-v02\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/v-02/classes/01/classes_07.py
groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]
Process finished with exit code 0
12.8. Script [classes_08]: creazione di una classe derivata dalla classe Persona
Nel modulo [myclasses] definiamo la seguente classe [Enseignant]:
# classe Insegnante
class Enseignant(Personne):
# costruttore
def __init__(self, prénom: str = "x", nom: str = "x", âge: int = 0, discipline: str = "x"):
# nome: nome della persona
# cognome: cognome della persona
# età: età della persona
# materia: materia insegnata
# Iniziale del genitore
Personne.__init__(self, prénom, nom, âge)
# altre iniziali
self.discipline = discipline
# toString
def __str__(self) -> str:
return f"enseignant[{super().__str__()},{self.discipline}]"
# proprietà
@property
def discipline(self) -> str:
return self.__discipline
@discipline.setter
def discipline(self, discipline: str):
# la disciplina deve essere una stringa non vuota
if Utils.is_string_ok(discipline):
self.__discipline = discipline
else:
raise MyException("La discipline doit être une chaîne de caractères non vide")
- riga 2: dichiara la classe Enseignant come classe derivata dalla classe Personne. Una classe derivata possiede tutte le proprietà (attributi e metodi) della sua classe padre, oltre a quelle proprie;
- riga 13: la classe [Enseignant] definisce un nuovo attributo [discipline];
- riga 11: il costruttore della classe derivata Enseignant deve chiamare il costruttore della classe padre Personne trasmettendogli i parametri richiesti;
- riga 17: la funzione [super()] restituisce la classe padre. Qui si chiama la funzione [__str__] della classe padre;
- righe 19-30: si definiscono il getter e il setter del nuovo attributo [discipline];
Lo script [classes_08] utilizza la classe [Enseignant] nel modo seguente:
# si configura l'applicazione
import config
config = config.configure()
# il syspath è configurato - è possibile eseguire le importazioni
from myclasses import Personne, Enseignant
# ---------------------------------- main
# creazione di un array di oggetti Personne e derivati
groupe = [Enseignant("Paul", "Langevin", 48, "anglais"), Personne("Sylvie", "Lefur", 70)]
# identità di queste persone
for i in range(len(groupe)):
print(f"groupe[{i}]={groupe[i]}")
Note:
- riga 7: si importano le classi [Personne] e [Enseignant] definite nel file [myclasses.py];
- righe 11-14: si definisce un gruppo di persone di cui viene poi visualizzata l'identità;
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_08.py
groupe[0]=enseignant[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]
Process finished with exit code 0
12.9. Script [classes_09]: seconda classe derivata dalla classe Persona
Lo script [classes_09] introduce la classe [Etudiant] derivata dalla classe [Personne]. Quest'ultima è definita come segue nel modulo [myclasses]:
# classe Studente
class Etudiant(Personne):
# costruttore
def __init__(self: object, prénom: str = "x", nom: str = "y", âge: int = 0, formation: str = "x"):
Personne.__init__(self, prénom, nom, âge)
self.formation = formation
# toString
def __str__(self: object) -> str:
return f"étudiant[{super().__str__()},{self.formation}]"
# proprietà
@property
def formation(self) -> str:
return self.__formation
@formation.setter
def formation(self, formation: str):
# la formazione deve essere una stringa non vuota
if Utils.is_string_ok(formation):
self.__formation = formation
else:
raise MyException("La formation doit être une chaîne de caractères non vide")
Lo script [classes_09] utilizza la classe [Etudiant] nel modo seguente:
# si configura l'applicazione
import config
config = config.configure()
# il syspath è configurato - è possibile eseguire le importazioni
from myclasses import Personne, Enseignant, Etudiant
# ---------------------------------- main
# creazione di un array di oggetti Persona e derivati
groupe = [Enseignant("Paul", "Langevin", 48, "anglais"), Personne("Sylvie", "Lefur", 70),
Etudiant("Steve", "Boer", 22, "iup2 qualité")]
# identità di queste persone
for personne in groupe:
# visualizzazione della persona
print(personne)
Note:
- questo script è analogo al precedente.
Risultati
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/classes/01/classes_09.py
enseignant[[Paul,Langevin,48],anglais]
[Sylvie,Lefur,70]
étudiant[[Steve,Boer,22],iup2 qualité]
Process finished with exit code 0
12.10. Script [classes_10]: la proprietà [__dict__]
Lo script [classes_10] presenta la proprietà [__dict__] che useremo spesso in seguito:
# si configura l'applicazione
import config
config = config.configure()
# il syspath è configurato - è possibile eseguire le importazioni
from myclasses import Etudiant
# ---------------------------------- main
# creazione di uno studente
étudiant=Etudiant("Steve", "Boer", 22, "iup2 qualité")
# dizionario delle proprietà
print(étudiant.__dict__)
Commenti
- righe 1-4: l’applicazione viene configurata;
- riga 7: viene importata la classe [Etudiant];
- riga 11: istanza di uno studente;
- riga 13: utilizzo del metodo predefinito [__dict__] (2 caratteri sottolineati prima e dopo l'identificativo);
I risultati sono i seguenti:
- alla riga 2 si ottiene un dizionario le cui chiavi sono le proprietà dell’oggetto precedute dal nome della classe a cui appartengono. Useremo questo dizionario per creare un ponte tra oggetto e dizionario;