5. Classi e oggetti
Una classe è il modello da cui vengono creati gli oggetti. Si dice che un oggetto sia un'istanza di una classe.
5.1. Una classe oggetto
Programma (classes_01)
| # -*- coding=utf-8 -*-
class Objet:
"""une classe Objet vide"""
# any variable can have attributes by construction
obj1=Objet()
obj1.attr1="un"
obj1.attr2=100
# displays the
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
# modify object
obj1.attr2+=100
# displays the
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
# assigns object1 reference to object2
obj2=obj1
# modify obj2
obj2.attr2=0
# displays both objects
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
print "objet2=[{0},{1}]".format(obj2.attr1,obj2.attr2)
|
Note:
- riga 4: un'altra forma di commento. Preceduto da tre "", può estendersi su più righe;
- righe 3-4: una classe oggetto vuota;
- riga 7: istanziazione della classe Object;
- riga 17: copia di riferimento. Le variabili obj1 e obj2 sono due puntatori (riferimenti) allo stesso oggetto.
Risultati
| objet1=[un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
|
5.2. Una classe Person
Programma (classes_02)
| # -*- coding=utf-8 -*-
class Personne:
# class attributes
# undeclared - can be created dynamically
# method
def identite(self):
# a priori, uses non-existent attributes
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# attributes are public and can be created dynamically
p=Personne()
p.prenom="Paul"
p.nom="Langevin"
p.age=48
# method call
print "personne={0}\n".format(p.identite())
|
Note:
- righe 3-10: una classe con un metodo;
- Riga 8: ogni metodo in una classe deve avere l'oggetto
self — che fa riferimento all'oggetto corrente — come primo parametro.
Risultati
personne=[Paul,Langevin,48]
5.3. La classe Person con un costruttore
Programma (classes_03)
| # -*- coding=utf-8 -*-
class Personne:
# manufacturer
def __init__(self,prenom,nom,age):
self.prenom=prenom;
self.nom=nom;
self.age=age;
# method
def identite(self):
# a priori, uses non-existent attributes
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# a Person object
p=Personne("Paul","Langevin",48)
# method call
print "personne={0}\n".format(p.identite())
|
Note:
- riga 6: il costruttore della classe si chiama __init__. Come per gli altri metodi, il suo primo parametro è self;
- riga 18: un oggetto Person viene creato utilizzando il costruttore della classe.
Risultati
personne=[Paul,Langevin,48]
5.4. La classe Person con controlli di validità nel costruttore
Programma (classes_04)
| # -*- coding=utf-8 -*-
import re
# -------------------
# a proprietary exception class
class MyError(Exception):
pass
class Personne:
# manufacturer
def __init__(self,prenom="x",nom="x",age=0):
# first name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",prenom)
if not match:
raise MyError("Le prenom ne peut etre vide")
else:
self.prenom=match.groups()[0]
# name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",nom)
if not match:
raise MyError("Le nom ne peut etre vide")
else:
self.nom=match.groups()[0]
# age must be valid
match=re.match(r"^\s*(\d+)\s*$",str(age))
if not match:
raise MyError("l'age doit etre un entier positif")
else:
self.age=match.groups()[0]
def __str__(self):
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# a Person object
try:
p=Personne(" Paul "," Langevin ",48)
print "personne={0}".format(p)
except MyError, erreur:
print erreur
# another object Nobody
try:
p=Personne(" xx "," yy "," zz")
print "personne={0}".format(p)
except MyError, erreur:
print erreur
# another person
try:
p=Personne()
print "personne={0}".format(p)
except MyError, erreur:
print erreur
|
Note:
- righe 7-8: una classe MyError derivata dalla classe Exception. Non aggiunge alcuna funzionalità a quest'ultima. È presente solo per fornire un'eccezione personalizzata;
- Riga 13: il costruttore ha valori predefiniti per i suoi parametri. Pertanto, l'operazione p = Person() è equivalente a p = Person("x", "x", 0);
- Righe 15–9: viene verificato il parametro first_name. Non deve essere vuoto. Se lo è, viene generata l'eccezione MyError con un messaggio di errore;
- Righe 21–25: Lo stesso vale per il parametro last_name;
- righe 27–31: verifica dell'età;
- righe 33-34: la funzione __str__ sostituisce il metodo precedentemente chiamato identite;
- righe 38–42: istanziare una Person e visualizzarne l'identità;
- riga 39: istanziazione;
- riga 40: visualizzazione. L'operazione richiede la visualizzazione della persona p come stringa. L'interprete Python chiama quindi automaticamente il metodo p.__str__() se esiste. Questo metodo ha lo stesso scopo del metodo toString() nei linguaggi Java o .NET;
- righe 41–42: gestione di una potenziale eccezione MyError. Quindi visualizza il messaggio di errore associato all'eccezione;
- righe 44–48: come sopra per una seconda istanza di Person creata con parametri errati;
- righe 50–54: come sopra per una terza istanza di Person creata con i parametri predefiniti.
Risultati
| personne=[Paul,Langevin,48]
l'age doit etre un entier positif
personne=[x,x,0]
|
5.5. Aggiunta di un metodo che funge da secondo costruttore
Programma (classes_05)
| # -*- coding=utf-8 -*-
import re
# -------------------
# a proprietary exception class
class MyError(Exception):
pass
class Personne:
# class attributes
# undeclared - can be created dynamically
# manufacturer
def __init__(self,prenom="x",nom="x",age=0):
# first name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",prenom)
if not match:
raise MyError("Le prenom ne peut etre vide")
else:
self.prenom=match.groups()[0]
# name must be non-empty
match=re.match(r"^\s*(\S+)\s*$",nom)
if not match:
raise MyError("Le nom ne peut etre vide")
else:
self.nom=match.groups()[0]
# age must be valid
match=re.match(r"^\s*(\d+)\s*$",str(age))
if not match:
raise MyError("l'age doit etre un entier positif")
else:
self.age=match.groups()[0]
def initWithPersonne(self,p):
# initializes the current object with a person p
self.__init__(p.prenom,p.nom,p.age)
def __str__(self):
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# a Person object
try:
p0=Personne(" Paul "," Langevin ",48)
print "personne={0}".format(p0)
except MyError, erreur:
print erreur
# another object Nobody
try:
p1=Personne(" xx "," yy "," zz")
print "personne={0}".format(p1)
except MyError, erreur:
print erreur
# another person
p2=Personne()
try:
p2.initWithPersonne(p0)
print "personne={0}".format(p2)
except MyError, erreur:
print erreur
|
Note:
- La differenza rispetto allo script precedente si trova alle righe 35–37. Abbiamo aggiunto il metodo
initWithPerson. Questo metodo richiama il costruttore \_\_init\_\_. A differenza dei linguaggi tipizzati, non è possibile avere metodi con lo stesso nome che si distinguano per la natura dei loro parametri o dei loro valori di ritorno. Pertanto, non è possibile avere più costruttori che creino l'oggetto a partire da parametri diversi, in questo caso un oggetto di tipo Person.
Risultati
| personne=[Paul,Langevin,48]
l'age doit etre un entier positif
personne=[Paul,Langevin,48]
|
5.6. Un elenco di oggetti Person
Programma (classes_06)
| # -*- coding=utf-8 -*-
class Personne:
...
# ---------------------------------- main
# create a list of person objects
groupe=[Personne("Paul","Langevin",48), Personne("Sylvie","Lefur",70)]
# identity of these persons
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
|
Note:
- Righe 3-5: la classe Person già descritta
Risultati
groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]
5.7. Creazione di una classe derivata dalla classe Person
Programma (classes_07)
| # -*- coding=utf-8 -*-
import re
class Personne:
...
class Enseignant(Personne):
def __init__(self,prenom="x",nom="x",age=0,discipline="x"):
Personne.__init__(self,prenom,nom,age)
self.discipline=discipline
def __str__(self):
return "[{0},{1},{2},{3}]".format(self.prenom,self.nom,self.age,self.discipline)
# ---------------------------------- main
# create a list of Personne objects and derivatives
groupe=[Enseignant("Paul","Langevin",48,"anglais"), Personne("Sylvie","Lefur",70)]
# identity of these persons
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
|
Note:
- righe 5-6: la classe Person è già definita;
- riga 8: dichiara la classe Teacher come sottoclasse della classe Person;
- riga 10: il costruttore della classe derivata Teacher deve chiamare il costruttore della classe padre Person;
- righe 21-22: per visualizzare group[i], l'interprete utilizza il metodo group[i].__str__(). Il metodo __str__() utilizzato è quello della classe effettiva di group[i], come mostrato nei risultati riportati di seguito.
Risultati
groupe[0]=[Paul,Langevin,48,anglais]
groupe[1]=[Sylvie,Lefur,70]
5.8. Creazione di una seconda classe derivata dalla classe Person
Programma (classes_08)
| # -*- coding=utf-8 -*-
import re
class Personne:
...
class Enseignant(Personne):
...
class Etudiant(Personne):
def __init__(self,prenom="x",nom="x",age=0,formation="x"):
Personne.__init__(self,prenom,nom,age)
self.formation=formation
def __str__(self):
return "[{0},{1},{2},{3}]".format(self.prenom,self.nom,self.age,self.formation)
# ---------------------------------- main
# create a list of Personne objects and derivatives
groupe=[Enseignant("Paul","Langevin",48,"anglais"), Personne("Sylvie","Lefur",70), Etudiant("Steve","Boer",22,"iup2 qualite")]
# identity of these persons
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
|
Note:
- Questo script è simile al precedente.
Risultati
groupe[0]=[Paul,Langevin,48,anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[Steve,Boer,22,iup2 qualite]