Klassen¶
Die objektorientierte Programmierung ist eine der effektivsten Vorgehensweisen zur Softwareentwicklung. Dabei schreiben Sie Klassen, die Dinge und Situationen in der Realität darstellen, und erstellen Objekte auf der Grundlage dieser Klassen.
Eine Klasse erstellen und verwenden¶
Mithilfe von Klassen können Sie fast alles modellieren. Als Einstieg wollen wir die einfache Klasse Dog schreiben, die für einen Hund steht – nicht für einen bestimmten Hund, sondern für Hunde im Allgemeinen.
Was wissen wir über Hunde, die als Haustiere gehalten werden?
Nun, sie alle haben einen Namen und ein Alter, und sie können sich hinsetzen und auf den Rücken rollen. Die beiden Informationen (Name und Alter) und die beiden Verhalten (Sitzen und Rollen) gehen in unsere Klasse Dog ein, da sie den meisten Hunden gemeinsam sind.
Die Klasse Dog erstellen¶
Jede Instanz der Klasse Dog hält den Namen (name) und das Alter (age) fest und gibt dem Hund eine Möglichkeit, sich zu setzen ( sit() ) und auf den Rücken zu rollen ( roll_over() ).
class Dog():
"""A simple attempt to model a dog."""
def __init__(self, name, age):
"""Initialize name and age attributes."""
self.name = name
self.age = age
def sit(self):
"""Simulate a dog sitting in response to a commadef __nd."""
print(f"{self.name} is now sitting.")
def roll_over(self):
"""Simulate rolling over in response to a command."""
print(f"{self.name} rolled over!")
Vereinbarungsgemäß bezeichnen Namen mit großem Anfangsbuchstaben in Python Klassen.
Die Methode __init__()¶
Eine Funktion, die zu einer Klasse gehört, wird als Methode bezeichnet.
Wir sehen die besondere Methode __init__(), die Python automatisch ausführt, wenn Sie eine neue Instanz auf der Grundlage der Klasse Dog erstellen.
Bemerkung
Eine Instanz einer Klasse in Python ist ein konkretes Objekt, das aus einer Klasse erzeugt wird.
Die Klasse dient dabei als Bauplan, der definiert, welche Eigenschaften (Attribute) und Verhaltensweisen (Methoden) die Instanzen haben.
Eine Instanz wird erstellt, indem die Klasse aufgerufen wird, und kann dann ihre eigenen Attributwerte besitzen und Methoden der Klasse nutzen.
Gemäß den Konventionen beginnt und endet der Methodenname jeweils mit zwei Unterstrichen, was Namenskonflikte zwischen den Standardmethoden von Python und Ihren eigenen Methoden verhindern hilft.
Wir definieren die Methode __init__() so, dass sie drei Parameter annimmt, nämlich self, name und age. Der Parameter self ist in der Methodendefinition erforderlich und muss vor allen weiteren stehen. Wenn Python später __init__() aufruft (um eine Instanz von Dog zu erstellen), übergibt der Methodenaufruf automatisch das Argument self.
Das macht jeder Aufruf einer Methode, die mit einer Klasse verknüpft ist. self ist ein Verweis auf die Instanz selbst und gibt der Instanz Zugriff auf die Attribute und Methoden in der Klasse.
Wenn wir eine Instanz von Dog erstellen, ruft Python __init__()aus der Klasse Dog auf. Dabei übergeben wir Dog() einen Namen und ein Alter als Argument. Da self automatisch übergeben wird, müssen wir das nicht selbst tun.
Wann immer wir eine Instanz der Klasse Dog erstellen wollen, geben wir nur Werte für die beiden letzten Parameter an, also für name und age.
Die beiden bei name und age definierten Variablen weisen jeweils das Präfix self auf. Dadurch stehen sie für alle Methoden in der Klasse zur Verfügung und sind auch über jede Instanz der Klasse zugänglich. self.name = name weist den Wert des Parameters name der Variablen name zu, die dann an die neu erstellte Instanz angehängt wird.
Das Gleiche geschieht bei self.age = age.
In der Klasse Dog sind noch zwei weitere Methoden definiert, nämlich sit() und roll_over() . Da sie keine weiteren Informationen wie einen Namen oder ein Alter benötigen, definieren wir sie einfach nur mit dem Parameter self. Die Instanzen, die wir später erstellen, haben Zugriff auf diese Methoden.
Vorläufig tun sit() und roll_over() noch nicht viel – sie geben einfach die Meldung aus, dass sich der Hund hinsetzt bzw. herumrollt.
Eine Instanz einer Klasse anlegen¶
Eine Klasse können Sie sich als einen Satz von Anweisungen vorstellen, die angeben, wie eine Instanz zu erstellen ist. Die Klasse Dog teilt Python also mit, wie es eine einzelne Instanz für einen bestimmten Hund anlegt. Genau das wollen wir mit folgendem Code erreichen:
class Dog():
-- schnipp --
my_dog = Dog('Willie', 6)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
Hier verwenden wir die Klasse Dog aus dem vorherigen Beispiel. Bei 5 weisen wir Python an, einen Hund mit dem Namen ‚Willie‘ und dem Alter 6 zu erstellen.
Wenn Python diese Zeile liest, ruft es die Methode init() in Dog mit den Argumenten Willie und 6 auf, die eine Instanz für diesen Hund anlegt und die Attribute name und age auf die angegebenen Werte setzt.
Zwar verfügt __init__() nicht über eine ausdrückliche return-Anweisung, Python gibt aber automatisch eine Instanz für den Hund zurück, die wir der Variablen my_dog zuweisen. Die Namenskonvention ist hier sehr hilfreich: Wir können davon ausgehen, dass ein Name mit großem Anfangsbuchstaben wie Dog zu einer Klasse gehört und ein kleingeschriebener Name wie my_dog zu einer einzelnen Instanz einer Klasse.
Zugriff auf die Attribute¶
Um auf die Attribute einer Instanz zuzugreifen, verwenden wir die Punktschreibweise.
Wir rufen wie folgt den Wert des Attributs name von my_dog ab:
my_dog.name
Methoden aufrufen¶
Nachdem wir eine Instanz der Klasse Dog erstellt haben, können wir jede in Dog definierte Methode mit der Punktschreibweise aufrufen. Um dafür zu sorgen, dass sich unser Hund hinsetzt und auf dem Boden rollt, gehen wir wie folgt vor:
class Dog():
-- schnipp --
my_dog = Dog('Willie', 6)
my_dog.sit()
my_dog.roll_over()
Um eine Methode aufzurufen, geben Sie den Namen der Instanz (hier: my_dog) gefolgt von einem Punkt und dann dem Methodennamen an. Wenn Python my_dog.sit() liest, sucht es in der Klasse Dog nach der Methode sit() und führt deren Code aus.
Wenn Attribute und Methoden beschreibende Namen wie name, age, sit() und roll_over() tragen, können wir leicht daraus schließen, was ein Codeblock tun soll, selbst wenn wir ihn nie zuvor gesehen haben.
Mehrere Instanzen erstellen¶
Von einer Klasse können Sie so viele Instanzen erstellen, wie Sie brauchen. Im Folgenden legen wir einen zweiten Hund mit der Bezeichnung your_dog an:
class Dog():
-- schnipp --
my_dog = Dog('Willie', 6)
your_dog = Dog('Lucy', 3)
print(f"My dog's name is {my_dog.name}.")
print(f"My dog is {my_dog.age} years old.")
my_dog.sit()
print(f"\nYour dog's name is {your_dog.name}.")
print(f"Your dog is {your_dog.age} years old.")
your_dog.sit()
Mit Klassen und Instanzen arbeiten:
class Auto():
def __init__(self, marke, model, jahr):
self.marke = marke
self.model = model
self.jahr = jahr
def get_descriptive_name(self):
long_name = f"{self.jahr} {self.marke} {self.model}"
return long_name.title()
mein_neues_auto = Auto('audi', 'a6', 2021)
print(mein_neues_auto.get_descriptive_name())
Um die Klasse interessanter zu machen, wollen wir noch ein Attribut hinzufügen, das sich mit der Zeit ändert – den Kilometerstand (»kilometerstand«).
Beim Erstellen einer Instanz können wir Attribute definieren, ohne sie als Parameter zu übergeben. Dies geschieht in der Methode __init__(), in der ihnen ein Standardwert zugewiesen wird.
Wir fügen das Attribut „kilometerstand“ hinzu und fügen die Methode „kilometerstand_lesen“ hinzu.
class Auto():
def __init__(self, marke, model, jahr):
self.marke = marke
self.model = model
self.jahr = jahr
self.kilometerstand = 0
def get_descriptive_name(self):
long_name = f"{self.jahr} {self.marke} {self.model}"
return long_name.title()
def kilometerstand_lesen(self):
print(f'Das Auto hat einen Kilometerstand von {self.kilometerstand} Kilometer.')
mein_neues_auto = Auto('audi', 'a6', 2021)
print(mein_neues_auto.get_descriptive_name())
mein_neues_auto.kilometerstand_lesen()
Da Autos normalerweise nicht mit einem Kilometerstand von genau 0 verkauft werden, brauchen wir eine Möglichkeit, um den Wert dieses Attributs zu ändern.
Attribute bearbeiten¶
Es gibt drei Möglichkeiten, um den Wert eines Attributs zu ändern: direkt in der Instanz, durch eine Methode oder durch Inkrementierung mithilfe einer Methode.
Sehen wir uns diese drei Vorgehensweisen genauer an:
Direkte Änderung eines Attributwertes¶
Die einfachste Möglichkeit, um den Wert eines Attributs zu ändern, besteht darin, über die Instanz direkt darauf zuzugreifen. Der folgende Code setzt den Kilometerstand auf diese Weise auf 23:
class Car():
-- schnipp --
my_new_car = Auto('audi', 'a4', 2019)
print(my_new_car.get_descriptive_name())
my_new_car.kilometerstand = 23
my_new_car.kilometerstand_lesen()
Kindklasse erstellen¶
Wir brauchen als erstes eine Elternklasse, die immer vor der Kindklasse im Code steht.
class Auto():
def __init__(self, marke, model, jahr):
self.marke = marke
self.model = model
self.jahr = jahr
self.kilometerstand = 0
def get_descriptive_name(self):
long_name = f"{self.jahr} {self.marke} {self.model}"
return long_name.title()
def kilometerstand_lesen(self):
print(f'Das Auto hat einen Kilometerstand von {self.kilometerstand} Kilometer.')
Dann erstellen wie eine Kindklasse, die alle Eigenschaften von der Klasse Auto erbt.
class ElectricCar(Auto):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""Initialize attributes of the parent class."""
super().__init__(make, model, year)
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
Attribute und Methoden der Kindklasse definieren¶
Einer Kindklasse können Sie neben den geerbten Elementen noch eigene Attribute und Methoden hinzufügen, die sie von ihrer Elternklasse unterscheiden.
Das wollen wir uns ansehen, indem wir ein Attribut hinzufügen, das es nur bei Elektroautos gibt (die Kapazität der Batterie), sowie eine Methode, die den Wert dieses Attributs ausgibt.
class ElectricCar(Car):
"""Represent aspects of a car, specific to electric vehicles."""
def __init__(self, make, model, year):
"""
Initialize attributes of the parent class.
Then initialize attributes specific to an electric car.
"""
super().__init__(make, model, year)
self.battery_size = 75
def describe_battery(self):
"""Print a statement describing the battery size."""
print(f"Das Auto hat eine {self.battery_size}-kWh Batterie.")
my_tesla = ElectricCar('tesla', 'model s', 2019)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery()