5. Klassen en objecten
Een klasse is de mal waaruit objecten worden gemaakt. Van een object wordt gezegd dat het een instantie van een klasse is.
![]() |
5.1. Een Object-klasse
Programma (classes_01)
# -*- coding=utf-8 -*-
class Objet:
"""une classe Objet vide"""
# elke variabele kan per definitie attributen hebben
obj1=Objet()
obj1.attr1="un"
obj1.attr2=100
# geeft het object weer
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
# wijzigt het object
obj1.attr2+=100
# geeft het object weer
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
# wijst de referentie van object1 toe aan object2
obj2=obj1
# wijzigt obj2
obj2.attr2=0
# geeft beide objecten weer
print "objet1=[{0},{1}]".format(obj1.attr1,obj1.attr2)
print "objet2=[{0},{1}]".format(obj2.attr1,obj2.attr2)
Opmerkingen:
- regel 4: een andere vorm van commentaar. Dit commentaar, voorafgegaan door drie "", kan zich over meerdere regels uitstrekken;
- regels 3-4: een lege objectklasse;
- regel 7: instantiatie van de klasse Objet;
- regel 17: kopiëren van verwijzingen. De variabelen obj1 en obj2 zijn twee pointers (verwijzingen) naar hetzelfde object.
Resultaten
5.2. Een klasse Persoon
Programma (classes_02)
# -*- coding=utf-8 -*-
class Personne:
# attributen van de klasse
# niet gedeclareerd – kunnen dynamisch worden aangemaakt
# methode
def identite(self):
# gebruikt a priori niet-bestaande attributen
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# de attributen zijn openbaar en kunnen dynamisch worden aangemaakt
p=Personne()
p.prenom="Paul"
p.nom="Langevin"
p.age=48
# aanroep van een methode
print "personne={0}\n".format(p.identite())
Opmerkingen:
- regels 3-10: een klasse met één methode;
- regel 8: elke methode van een klasse moet als eerste parameter het object self hebben, dat het huidige object aanduidt.
Resultaten
5.3. De klasse Personne met een constructor
Programma (classes_03)
# -*- coding=utf-8 -*-
class Personne:
# constructor
def __init__(self,prenom,nom,age):
self.prenom=prenom;
self.nom=nom;
self.age=age;
# methode
def identite(self):
# gebruikt a priori niet-bestaande attributen
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# een Personne-object
p=Personne("Paul","Langevin",48)
# aanroep van een methode
print "personne={0}\n".format(p.identite())
Opmerkingen:
- regel 6: de constructor van een klasse heet __init__. Net als bij de andere methoden is de eerste parameter self;
- regel 18: er wordt een object Personne aangemaakt met de constructor van de klasse.
Resultaten
5.4. De klasse Personne met validatiecontroles in de constructor
Programma (classes_04)
# -*- coding=utf-8 -*-
import re
# -------------------
# een eigen uitzonderingsklasse
class MyError(Exception):
pass
class Personne:
# constructor
def __init__(self,prenom="x",nom="x",age=0):
# de voornaam mag niet leeg zijn
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]
# de achternaam mag niet leeg zijn
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]
# de leeftijd moet geldig zijn
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)
# ---------------------------------- hand
# een object 'Persoon'
try:
p=Personne(" Paul "," Langevin ",48)
print "personne={0}".format(p)
except MyError, erreur:
print erreur
# een ander Person-object
try:
p=Personne(" xx "," yy "," zz")
print "personne={0}".format(p)
except MyError, erreur:
print erreur
# een andere persoon
try:
p=Personne()
print "personne={0}".format(p)
except MyError, erreur:
print erreur
Opmerkingen:
- regels 7-8: een klasse MyError die is afgeleid van de klasse Exception. Deze voegt geen functionaliteit toe aan de laatste. Ze is er alleen om een eigen uitzondering te hebben;
- regel 13: de constructor heeft standaardwaarden voor zijn parameters. De bewerking p=Personne() is dus gelijk aan p=Personne("x","x",0);
- regels 15-9: de parameter prenom wordt geanalyseerd. Deze mag niet leeg zijn. Als dat wel het geval is, wordt de uitzondering MyError met een foutmelding gegenereerd;
- regels 21-25: idem voor de naam;
- regels 27-31: controle van de leeftijd;
- regels 33-34: de functie __str__ vervangt de methode die voorheen identite heette;
- regels 38-42: een persoon instantiëren en vervolgens diens identiteit weergeven;
- regel 39: instantiëren;
- regel 40: weergave. De bewerking vraagt om de persoon p weer te geven in de vorm van een tekenreeks. De Python-interpreter roept dan automatisch de methode p.__str__() aan, indien deze bestaat. Deze methode vervult dezelfde rol als de methode toString() in Java of in de .NET-talen;
- regels 41-42: afhandeling van een eventuele uitzondering van het type MyError. Geeft vervolgens het foutbericht weer dat bij de uitzondering hoort;
- regels 44-48: idem voor een tweede persoon die met onjuiste parameters is geïnstantieerd;
- regels 50-54: idem voor een derde persoon die met de standaardparameters is geïnstantieerd.
Resultaten
5.5. Toevoeging van een methode die als tweede constructor fungeert
Programma (classes_05)
# -*- coding=utf-8 -*-
import re
# -------------------
# een eigen uitzonderingsklasse
class MyError(Exception):
pass
class Personne:
# attributen van de klasse
# niet gedeclareerd – kunnen dynamisch worden aangemaakt
# constructor
def __init__(self,prenom="x",nom="x",age=0):
# de voornaam mag niet leeg zijn
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]
# de achternaam mag niet leeg zijn
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]
# de leeftijd moet geldig zijn
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):
# initialiseert het huidige object met een persoon p
self.__init__(p.prenom,p.nom,p.age)
def __str__(self):
return "[{0},{1},{2}]".format(self.prenom,self.nom,self.age)
# ---------------------------------- main
# een Person-object
try:
p0=Personne(" Paul "," Langevin ",48)
print "personne={0}".format(p0)
except MyError, erreur:
print erreur
# een ander Person-object
try:
p1=Personne(" xx "," yy "," zz")
print "personne={0}".format(p1)
except MyError, erreur:
print erreur
# een andere persoon
p2=Personne()
try:
p2.initWithPersonne(p0)
print "personne={0}".format(p2)
except MyError, erreur:
print erreur
Opmerkingen:
- het verschil met het vorige script zit in de regels 35-37. We hebben de methode initWithPersonne toegevoegd. Deze maakt gebruik van de constructor __init__. Het is niet mogelijk om, zoals in getypeerde talen, methoden met dezelfde naam te hebben die worden onderscheiden door de aard van hun parameters of hun resultaat. Het is dus niet mogelijk om meerdere constructors te hebben die het object op basis van verschillende parameters zouden construeren, in dit geval een object van het type Personne.
Resultaten
5.6. Een lijst met Personne-objecten
Programma (classes_06)
# -*- coding=utf-8 -*-
class Personne:
...
# ---------------------------------- main
# aanmaken van een lijst met Personen-objecten
groupe=[Personne("Paul","Langevin",48), Personne("Sylvie","Lefur",70)]
# identiteit van deze personen
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
Opmerkingen:
- regels 3-5: de reeds beschreven klasse Personne
Resultaten
5.7. Aanmaken van een klasse die is afgeleid van de klasse Persoon
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)
# ---------------------------------- hand
# aanmaken van een lijst met objecten 'Persoon' en afgeleiden
groupe=[Enseignant("Paul","Langevin",48,"anglais"), Personne("Sylvie","Lefur",70)]
# identiteit van deze personen
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
Opmerkingen:
- regels 5-6: de reeds gedefinieerde klasse Personne;
- regel 8: verklaart de klasse Enseignant als een afgeleide klasse van de klasse Personne;
- regel 10: de constructor van de afgeleide klasse Enseignant moet de constructor van de bovenliggende klasse Personne aanroepen;
- regels 21-22: om groep[i] weer te geven, gebruikt de interpreter de methode groep[i].__str__(). De gebruikte methode __str__() is die van de daadwerkelijke klasse van groep[i], zoals uit de onderstaande resultaten blijkt.
Resultaten
5.8. Aanmaken van een tweede klasse die is afgeleid van de klasse Personne
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)
# ---------------------------------- hand
# aanmaken van een lijst met objecten van het type 'Persoon' en afgeleiden
groupe=[Enseignant("Paul","Langevin",48,"anglais"), Personne("Sylvie","Lefur",70), Etudiant("Steve","Boer",22,"iup2 qualite")]
# identiteit van deze personen
for i in range(len(groupe)):
print "groupe[{0}]={1}".format(i,groupe[i])
Opmerkingen:
- dit script is vergelijkbaar met het vorige.
Resultaten
