5. Klassen und Objekte
Eine Klasse ist die Vorlage, aus der Objekte erstellt werden. Ein Objekt wird als Instanz einer Klasse bezeichnet.
5.1. Eine Objektklasse
Programm (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)
|
Anmerkungen:
- Zeile 4: eine weitere Form des Kommentars. Vorangestellt sind drei „“, er kann sich über mehrere Zeilen erstrecken;
- Zeilen 3–4: eine leere Objektklasse;
- Zeile 7: Instanziierung der Klasse „Object“;
- Zeile 17: Referenzkopie. Die Variablen obj1 und obj2 sind zwei Zeiger (Referenzen) auf dasselbe Objekt.
Ergebnisse
| objet1=[un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
|
5.2. Eine Person-Klasse
Programm (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())
|
Anmerkungen:
- Zeilen 3–10: eine Klasse mit einer Methode;
- Zeile 8: Jede Methode in einer Klasse muss das
self-Objekt – das sich auf das aktuelle Objekt bezieht – als ersten Parameter haben.
Ergebnisse
personne=[Paul,Langevin,48]
5.3. Die Klasse „Person“ mit einem Konstruktor
Programm (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())
|
Anmerkungen:
- Zeile 6: Der Klassenkonstruktor heißt __init__. Wie bei anderen Methoden ist sein erster Parameter self;
- Zeile 18: Ein Person-Objekt wird mithilfe des Klassenkonstruktors erstellt.
Ergebnisse
personne=[Paul,Langevin,48]
5.4. Die Klasse „Person“ mit Gültigkeitsprüfungen im Konstruktor
Programm (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
|
Anmerkungen:
- Zeilen 7–8: Eine MyError-Klasse, die von der Exception-Klasse abgeleitet ist. Sie fügt dieser keine neuen Funktionen hinzu. Sie dient lediglich dazu, eine benutzerdefinierte Ausnahme bereitzustellen;
- Zeile 13: Der Konstruktor hat Standardwerte für seine Parameter. Daher entspricht die Operation p = Person() der Operation p = Person("x", "x", 0);
- Zeilen 15–19: Der Parameter first_name wird überprüft. Er darf nicht leer sein. Ist er es doch, wird die Ausnahme MyError mit einer Fehlermeldung ausgelöst;
- Zeilen 21–25: Dasselbe gilt für „last_name“;
- Zeilen 27–31: Altersüberprüfung;
- Zeilen 33–34: Die Funktion __str__ ersetzt die zuvor aufgerufene Methode identite;
- Zeilen 38–42: Instanziierung einer Person und Anzeige ihrer Identität;
- Zeile 39: Instanziierung;
- Zeile 40: Anzeige. Der Vorgang erfordert die Darstellung der Person p als Zeichenkette. Der Python-Interpreter ruft dann automatisch die Methode p.__str__() auf, sofern diese existiert. Diese Methode erfüllt denselben Zweck wie die Methode toString() in Java oder .NET-Sprachen;
- Zeilen 41–42: Behandlung einer möglichen MyError-Ausnahme. Anschließend wird die mit der Ausnahme verbundene Fehlermeldung angezeigt;
- Zeilen 44–48: wie oben für eine zweite Instanz von „Person“, die mit falschen Parametern erstellt wurde;
- Zeilen 50–54: wie oben für eine dritte Person, die mit Standardparametern instanziiert wurde.
Ergebnisse
| personne=[Paul,Langevin,48]
l'age doit etre un entier positif
personne=[x,x,0]
|
5.5. Hinzufügen einer Methode, die als zweiter Konstruktor fungiert
Programm (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
|
Anmerkungen:
- Der Unterschied zum vorherigen Skript liegt in den Zeilen 35–37. Wir haben die Methode
initWithPerson hinzugefügt. Diese Methode ruft den Konstruktor \_\_init\_\_ auf. Anders als in typisierten Sprachen ist es nicht möglich, Methoden mit demselben Namen zu haben, die sich durch die Art ihrer Parameter oder ihrer Rückgabewerte unterscheiden. Daher ist es nicht möglich, mehrere Konstruktoren zu haben, die das Objekt aus unterschiedlichen Parametern erstellen würden, in diesem Fall ein Objekt vom Typ Person.
Ergebnisse
| personne=[Paul,Langevin,48]
l'age doit etre un entier positif
personne=[Paul,Langevin,48]
|
5.6. Eine Liste von Person-Objekten
Programm (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])
|
Anmerkungen:
- Zeilen 3–5: die bereits beschriebene Klasse „Person“
Ergebnisse
groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]
5.7. Erstellen einer von der Klasse „Person“ abgeleiteten Klasse
Programm (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])
|
Anmerkungen:
- Zeilen 5–6: Die Klasse „Person“ ist bereits definiert;
- Zeile 8: Deklariert die Klasse „Teacher“ als Unterklasse der Klasse „Person“;
- Zeile 10: Der Konstruktor der abgeleiteten Klasse „Teacher“ muss den Konstruktor der übergeordneten Klasse „Person“ aufrufen;
- Zeilen 21–22: Um group[i] anzuzeigen, verwendet der Interpreter die Methode group[i].__str__(). Die verwendete Methode __str__() ist die der tatsächlichen Klasse von group[i], wie in den folgenden Ergebnissen gezeigt.
Ergebnisse
groupe[0]=[Paul,Langevin,48,anglais]
groupe[1]=[Sylvie,Lefur,70]
5.8. Erstellen einer zweiten Klasse, die von der Klasse „Person“ abgeleitet ist
Programm (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])
|
Anmerkungen:
- Dieses Skript ähnelt dem vorherigen.
Ergebnisse
groupe[0]=[Paul,Langevin,48,anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[Steve,Boer,22,iup2 qualite]