mitmario.dev

Methoden

Python Sandbox 3 Min Lesezeit 4 BeispieleLektion 2 von 6

zeile() aus der Aufgabe mit den Konten fragt nach inhaber und stand. Mit etwas anderem als einem Konto kann sie also nichts anfangen, und sie hat auch nie etwas anderes bekommen. Eine Funktion, die nur für eine Klasse da ist, gehört in diese Klasse. Dort heißt sie Methode (method). Das Wort kennst du schon von den Listen, append ist eine Methode der Liste und upper eine von Text.

Eine Methode, die rechnet

Eine Methode, die rechnet
class Artikel:
    def __init__(self, name, preis, bestand):
        self.name = name
        self.preis = preis
        self.bestand = bestand

    def wert(self):
        return self.preis * self.bestand


brot = Artikel("Brot", 2.49, 12)
milch = Artikel("Milch", 1.19, 30)

print(f"{brot.name}: {brot.wert():.2f} Euro im Regal")
print(f"{milch.name}: {milch.wert():.2f} Euro im Regal")
print(f"Dasselbe: {Artikel.wert(brot):.2f} Euro")

wert steht eingerückt in der Klasse, wie __init__, und ihr erster Parameter ist wieder self. Aufgerufen wird sie mit einem Punkt an einem Objekt, also brot.wert(). Python macht daraus Artikel.wert(brot). So steht es auch in der letzten Zeile, und das Ergebnis ist dasselbe.

Was vor dem Punkt steht, landet in self. Deshalb rechnet dieselbe Methode beim Brot mit 2.49 Euro und 12 Stück und bei der Milch mit deren eigenen Werten. Mitgeben musst du ihr dafür nichts.

Nicht alles gehört in die Klasse. Was ein Artikel mit sich selbst macht, wird eine Methode. Was über viele Artikel geht, etwa der Wert des ganzen Regals, bleibt eine Funktion, die eine Liste bekommt.

Eine Methode, die ändert

Eine Methode, die ändert
class Artikel:
    def __init__(self, name, preis, bestand):
        self.name = name
        self.preis = preis
        self.bestand = bestand

    def verkaufe(self, menge):
        self.bestand = self.bestand - menge


brot = Artikel("Brot", 2.49, 12)
brot.verkaufe(3)
brot.verkaufe(2)
print(brot.bestand)
print(brot.verkaufe(1))
print(brot.bestand)

verkaufe rechnet nichts aus. Die Methode ändert den Bestand des Objekts, an dem sie aufgerufen wird, und nach zwei Verkäufen sind vom Brot noch 7 Stück da. Zurück gibt sie nichts, also None.

Das kennst du schon von liste.sort() aus Lektion 5.4, das die Liste selbst sortiert und ebenfalls None zurückgibt. In Python ist das die Regel, mit wenigen Ausnahmen wie pop bei den Listen. Eine Methode, die etwas ausrechnet, gibt es zurück und lässt das Objekt in Ruhe. Eine, die das Objekt ändert, gibt nichts zurück. So sieht man schon am Aufruf, womit man es zu tun hat.

Eine Funktion, die eine Variable von außen ändern will, braucht dafür global oder ein return. verkaufe braucht keins von beiden. Der Bestand gehört dem Objekt, und das Objekt steckt in self.

Ablehnen, bevor sich etwas ändert

Verkaufen, was nicht da ist
class Artikel:
    def __init__(self, name, preis, bestand):
        self.name = name
        self.preis = preis
        self.bestand = bestand

    def verkaufe(self, menge):
        if menge > self.bestand:
            raise ValueError(f"Nur noch {self.bestand} Stück {self.name} da")
        self.bestand = self.bestand - menge


butter = Artikel("Butter", 2.29, 4)
for menge in [3, 2, 1]:
    try:
        butter.verkaufe(menge)
        print(f"{menge} verkauft, noch {butter.bestand} da")
    except ValueError as fehler:
        print("Abgelehnt:", fehler)

Mehr Butter verkaufen, als da ist, sollte nicht gehen. Wie bei der Überweisung wird das mit raise ValueError abgelehnt, und wer die Methode aufruft, fängt den Fehler mit try. Neu ist die Reihenfolge. Erst wird geprüft, dann geändert. Nach dem Nein zu zwei Stück ist deshalb noch eins da, und das letzte geht über die Theke.

Andersherum wäre es ein stiller Fehler. Würde die Methode erst abziehen und dann prüfen, stünde nach dem abgelehnten Verkauf ein Bestand von -1 im Objekt, obwohl nichts verkauft wurde. Bei einer Funktion, die nur etwas zurückgibt, kann das nicht passieren, denn ohne Rückgabe bleibt alles, wie es war. Bei einer Methode bleibt stehen, was sie vor dem raise schon geändert hat.

Ein self fehlt

Ein self fehlt in der Methode
class Artikel:
    def __init__(self, name, preis, bestand):
        self.name = name
        self.preis = preis
        self.bestand = bestand

    def wert():
        return self.preis * self.bestand


brot = Artikel("Brot", 2.49, 12)
print(brot.wert())

Ohne self steht da def wert():. Aufgerufen wird brot.wert() mit leeren Klammern, und Python antwortet mit TypeError: Artikel.wert() takes 0 positional arguments but 1 was given.

Gegeben hast du keins. Python zählt trotzdem eins, und das ist das Objekt selbst, das bei jedem Aufruf mit Punkt als erstes Argument mitgeht. Wer die Meldung einmal so gelesen hat, weiß, was self ist.

Was die Aufgabe will

Das Konto mit Inhaber und Stand bekommt zwei Methoden, einzahlen und abheben. Es gelten die Regeln aus Lektion 9.4, also nur Beträge über null und nicht mehr abheben, als da ist.

Zum Mitnehmen

Eine Methode ist eine Funktion, die in der Klasse steht. Aus brot.wert() macht Python Artikel.wert(brot), das Objekt vor dem Punkt wird also zu self. Methoden, die rechnen, geben ein Ergebnis zurück, Methoden, die ändern, geben None zurück, und ein raise gehört vor die erste Änderung, damit nach dem Nein kein halber Stand übrig bleibt.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe, dein Code läuft auf einem Server

    Öffnet sich mit dem Basis Konto.