18.1. Klassen und Objekte#
Eine Klasse ist die Blaupause seiner Objekte.
Klassen
Eine Klasse ist ein zusammengesetzter Datentyp der Methoden definiert, die allesamt auf Werte des eigenen Typs angewendet werden können. Eine Klasse definiert eine Blaupause für ein Bündel aus Daten und Funktionen, welche wir Methoden nennen.
Und ein Objekt ist eine konkrete Instanz einer Klasse, d.h. eine Variable eines zusammengesetzte Datentyp belegt mit bestimmten Werten und ausgestattet mit Methoden der Klasse.
Objekte in Python
In Python
ist alles (auch Werte von atomaren Datentypen) ein Objekt.
Es kann viele Objekte einer Klasse geben. Jedes Objekt liegt als Datenbündel im Speicher. Jedes Objekt einer bestimmten Klasse beinhaltet andere Werte, doch sind die Methoden aller Objekte einer Klasse identisch.
18.1.1. Klassen#
Eine Klasse ist eine Definition eines zusammengesetzten Datentyps angereichert mit Methoden, die auf dem Datentyp ausgeführt werden sollen.
Sie ist ein Codeblock der mit dem class
-Ausdruck beginnt:
class ClassName(Superclass):
def __init__(self, arguments):
# define or assign object attributes
def other_method(self, arguments):
# body of the method
Ähnlich wie eine Funktion, müssen wir eine Klasse zuerst definieren bevor wir sie nutzten können.
Doch anders als Funktionen, schreibt man Klassennamen (hier ClassName
) in CamelCase/CamelCaps.
Superclass
ist optional und ist die Klasse von der ClassName
erbt.
Was das bedeutet, werden wir im Abschnitt Vererbung besprechen.
Methoden der Form __method_name__()
, sind spezielle Python
-Methoden die eine vordefinierte Bedeutung besitzen.
Die voran- und nachgestellten doppelten Unterstriche deuten an, dass diese Methoden für spezielle Zwecke reserviert sind.
__init__()
wird ausgeführt sobald ein Objekt der Klasse instanziiert / erzeugt wurde.
Genau genommen ist __init__()
nicht der Konstruktor, sondern wird direkt nach dem Konstruktor aufgerufen.
In Python
definieren wir den Konstruktor nicht explizit.
__init__()
füllt das Objekt mit seinen Daten bevor das Objekt benutzt wird.
Konstruktor
Als Konstruktor bezeichnen wir eine spezielle Methode einer Klasse, die beim Erzeugen des Objekts der Klasse aufgerufen wird. Die Methode erzeugt das Objekt, d.h., diese Methode reserviert Speicher und legt es das Objekt in den Arbeitsspeicher, an die entsprechende Speicheradresse.
Die Methode other_method
ist eine Funktion des Objekts der Klasse ClassName
.
Es wird Ihnen aufgefallen sein, dass jede der Methoden als ersten Parameter self
definiert.
Jede Klassenmethode muss diesen Extraparameter self
besitzen.
Der Wert dieses ersten Parameters wird automatisch mit dem Objekt selbst initialisiert.
Durch dieses self
können wir auf alle Attribute und Methoden des Objekts zugreifen (auch die privaten).
Greifen wir auf Attribute oder Methoden des Objekts zu, so müssen wir den Weg über den self
-Parameter gehen.
Blicken wir auf ein Beispiel.
Wir definieren eine neue Klasse Student
mit den Attributen sid
(id der Studierenden), name
, type
und age
.
Wir definieren eine Methode say_name
welche Informationen über den Studierenden ausgibt.
Alle Attribute bis auf type
werden bei der Objekterzeugung übergeben.
class Student():
def __init__(self, sid, name, age):
self.sid = sid
self.name = name
self.age = age
self.type = 'learning'
def say_name(self):
print(f'My name is {self.name}.')
Sie sehen wie wir über self.attributename
auf die Attribute des Objekts zugreifen können.
Für Methoden gilt diese Regel ebenso.
Lassen Sie uns dies veranschaulichen, indem wir unsere Klasse um eine weitere Methode report
erweitern.
class Student():
def __init__(self, sid, name, age):
self.sid = sid
self.name = name
self.age = age
self.type = 'learning'
def say_name(self):
print(f'My name is {self.name}.')
def report(self, score):
self.say_name()
print(f'My id is: {self.sid}')
print(f'My age is: {self.age}')
print(f'My score is: {score}')
report
ruft die Methode say_name
durch self.say_name()
auf.
Beachten Sie, dass wir das self
nicht als Argument übergeben müssen!
Der Interpreter wandelt self.say_name()
zu say_name(self)
um.
In report
übergeben wir ein weiteres Argument score
, welches wir wie gewöhnt durch seinen Namen ansprechen können.
18.1.2. Objekte#
Ein Objekt ist eine Instanz einer Klasse. Die Klasse ist der Datentyp und das Objekt ist ein Wert vom Typ der Klasse angereichert mit den Methoden, die in der Klasse definiert wurden. Wir können viele verschiedene und auch gleiche Objekte einer Klasse erzeugen. Die Klasse können wir als den Bauplan der Objekte verstehen.
Objekte
Ein Objekt ist eine konkrete Instanz einer Klasse.
Rufen wir Methoden eines Objekts auf, müssen wir das erste spezielle self
-Argument nicht angeben.
Eine Methode methodname
des Objekts objectname
rufen wir durch
objectname.methodname(arguments)
auf.
Ein solcher Aufruf wird auch als Nachricht, die wir an einen Empfänger schicken, verstanden.
Dabei ist die Nachricht gleich methodname(arguments)
und der Empfänger ist das Objekt objectname
.
Diese Analogie wird deutlich wenn wir uns an den Roboter robo
erinnern.
Diesen haben wir mit der Nachricht move()
gesagt, er solle sich bewegen.
Auch im folgenden Beispiel können wir Methodenaufrufe als Anweisungen oder Nachrichten die an das Objekt gesendet werden verstehen:
student1 = Student("001", "Susan", 24)
student2 = Student("002", "Mike", 23)
student1.say_name()
student2.say_name()
print(student1.type)
print(student1.age)
print()
student2.report(331)
My name is Susan.
My name is Mike.
learning
24
My name is Mike.
My id is: 002
My age is: 23
My score is: 331
Im obigen Beispiel erzeugen wir zwei Instanzen student1
, student2
der Klasse Student
.
Die Daten der Objekte unterscheiden sich, doch deren Methoden sind identisch.
Rufen wir report
auf, so wird intern (innerhalb des Objekts) die Methode say_name
aufgerufen.
18.1.3. Klassenattribute#
self.attributename
sind Attribute des Objekts.
Diese können für jedes Objekt einen anderen Wert besitzen.
Klassenattribute sind hingegen Attribute einer Klasse und da es nur eine Klasse eines bestimmten Typs gibt, teilen sich alle Objekte einer Klasse deren Klassenattribute.
Wir definieren Klassenattribute indem wir das self
weglassen und diese außerhalb jedweder Methode niederschreiben.
Um ein Klassenattribute zu verwenden, müssen wir den Klassennamen voranstellen, d.h. ClassName.attributename
.
Im folgenden Fall führen wir ein Klassenattribut n_instances
ein, welches die Anzahl der erzeugten Objekte der Klasse Student
beinhaltet.
class Student():
n_instances = 0
def __init__(self, sid, name, age):
self.sid = sid
self.name = name
self.age = age
self.type = 'learning'
Student.n_instances +=1
def say_name(self):
print(f'My name is {self.name}.')
def report(self, score):
self.say_name()
print(f'My id is: {self.sid}')
print(f'My age is: {self.age}')
print(f'My score is: {score}')
def num_instances(self):
print(f'We have {Student.n_instances}-instance in total')
Lassen Sie uns den Code testen:
student1 = Student("001", "Susan", 23)
student1.num_instances()
student2 = Student("002", "Mike", 25)
student1.num_instances()
student2.num_instances()
We have 1-instance in total
We have 2-instance in total
We have 2-instance in total
Wir erzeugen zwei Objekte, doch lediglich sid
, name
und age
gehören zu einem bestimmten Objekt.
student1.name
hat den Wert "Susan"
und student2.name
hat den Wert "Mike"
.
Doch n_instances
wird objektübergreifend geteilt.
Bei der Erzeugung der Klasse wird n_instances
auf den Wert 0
gesetzt.
Immer wenn wir ein Student
-Objekt erzeugen, erhöht sich das Klassenattribut n_instances
um eins.
Klassenattribute
Klassenattribute sollten sparsam eingesetzt werden und sollten niemals dazu verwendet werden um das Verhalten eines Objekts zu beeinflussen! Das Verhalten muss sich stets aus der Kombination von Objektattributen und Methoden ergeben.