Bisher hast du Daten (Variablen) und Funktionen getrennt behandelt. Bei der objektorientierten Programmierung (OOP) fasst du beides zusammen: Ein Objekt hat Eigenschaften (Daten) und Fähigkeiten (Funktionen). Die Bauanleitung dafür heißt Klasse.
Du kennst Objekte schon: Ein str ist ein Objekt mit Methoden wie .upper(), eine list eins mit .append().
Eine Klasse definieren
class Hund:
def __init__(self, name, alter):
self.name = name
self.alter = alter
def bellen(self):
return f"{self.name} sagt: Wuff!"
rex = Hund("Rex", 3)
mimi = Hund("Mimi", 5)
print(rex.name, rex.alter)
print(rex.bellen())
print(mimi.bellen())
print(type(rex))Rex 3 Rex sagt: Wuff! Mimi sagt: Wuff! <class '__main__.Hund'>
Was hier passiert:
class Hund:legt die Klasse an (Namen schreibt man in CamelCase).__init__ist der Konstruktor: Er läuft automatisch, wenn duHund(...)aufrufst, und setzt die Anfangswerte.selfist das Objekt selbst. Es steht in jeder Methode als erster Parameter, beim Aufruf übergibt Python es automatisch.self.name = namespeichert einen Wert als Attribut des Objekts.rexundmimisind zwei unabhängige Instanzen derselben Klasse.
Attribute ändern
class Konto:
def __init__(self, inhaber, stand=0):
self.inhaber = inhaber
self.stand = stand
def einzahlen(self, betrag):
self.stand += betrag
def abheben(self, betrag):
if betrag > self.stand:
raise ValueError("Nicht genug Guthaben")
self.stand -= betrag
k = Konto("Mia", 100)
k.einzahlen(50)
k.abheben(30)
print(k.stand)
try:
k.abheben(1000)
except ValueError as e:
print("Fehler:", e)120 Fehler: Nicht genug Guthaben
Klassenattribute
Ein Attribut, das direkt in der Klasse steht, gehört allen Instanzen gemeinsam:
class Zaehler:
anzahl = 0 # Klassenattribut
def __init__(self):
Zaehler.anzahl += 1
Zaehler()
Zaehler()
c = Zaehler()
print(Zaehler.anzahl, c.anzahl)3 3
Lesbare Ausgabe mit __str__ und __repr__
Ohne Hilfe zeigt print(objekt) nur eine Speicheradresse. Mit __str__ bestimmst du den Text für Menschen, mit __repr__ die eindeutige Darstellung für Entwickler:
class Punkt:
def __init__(self, x, y):
self.x, self.y = x, y
def __str__(self):
return f"({self.x}|{self.y})"
def __repr__(self):
return f"Punkt({self.x}, {self.y})"
p = Punkt(2, 5)
print(p)
print([p, Punkt(0, 0)])
print(repr(p))(2|5) [Punkt(2, 5), Punkt(0, 0)] Punkt(2, 5)
Kapselung und Konventionen
Python kennt kein striktes private. Stattdessen gibt es Konventionen:
| Schreibweise | Bedeutung |
|---|---|
name | öffentlich |
_name | "intern", bitte nicht von außen anfassen |
__name | wird umbenannt (name mangling), schützt vor versehentlichem Überschreiben in Unterklassen |
Methodenarten
class Kreis:
PI = 3.14159
def __init__(self, r):
self.r = r
def flaeche(self): # normale Methode (braucht self)
return Kreis.PI * self.r ** 2
@classmethod
def aus_durchmesser(cls, d): # alternativer Konstruktor
return cls(d / 2)
@staticmethod
def ist_gueltig(r): # braucht weder self noch cls
return r > 0
k = Kreis.aus_durchmesser(10)
print(k.r, round(k.flaeche(), 2), Kreis.ist_gueltig(-1))5.0 78.54 False
Merke
- Eine Klasse ist eine Bauanleitung, ein Objekt (Instanz) ein daraus gebautes Exemplar
__init__setzt die Anfangswerte,selfist das aktuelle Objekt- Attribute speichern Daten, Methoden sind Funktionen der Klasse
__str__für Menschen,__repr__für Entwickler@classmethodund@staticmethodfür Methoden ohne Instanz_namebedeutet "intern" (nur Konvention)
Aufgabe
Schreibe eine Klasse Rechteck mit Breite und Höhe, einer Methode flaeche() und einer Methode umfang().