Python OOP: Statische Member und Type-Annotation

https://oer-informatik.de/python_oop_static

https://bildung.social/@oerinformatik

tl/dr; (ca. 10 min Lesezeit): Neben Methoden und Instanzvariablen (Attributen), die das Verhalten und den Zustand einzelner Objekte speichern und verändern gibt es in der objektorientierten Programmierung auch Verhalten und Zustand, der einen gemeinsamen Zustand aller Objekte einer Klasse betrifft. Solche Klassenmethoden und Klassenvariablen werden in der OOP statisch genannt. Dieser Artikel beschreibt, wie sie in Python implementiert werden. (Zuletzt geändert am 02.03.2024)

Neben dem Objektzustand und dem Objektverhalten kann es auch Zustände und Verhalten geben, das an die Klasse gebunden ist - also nicht abhängt von Instanzvariablen.

Man speichert den Zustand einer Klasse, der nicht von einer Instanz abhängt, in statischen Variablen (manchmal spricht man auch von Klassenvariablen). Methoden, die keinen Objektzustand nutzen heißen entsprechend statische Methoden oder Klassenmethoden.

Ein einfaches Beispiel wäre eine Liste, die alle Instanzen einer Klasse speichert und Methoden, die diese Liste managen.

Statische Attribute / Klassenvariablen

Sofern das Attribut konten von allen Instanzen der Klasse Konto gleichermaßen genutzt werden soll, spricht man von einem statischen Attribut. In diesem Beispiel stellt konten eine Liste dar, in der alle Instanzen der Klasse gesammelt werden.

In Python wird ein statisches Attribut immer über den Klassennamen angesprochen (hier: Konten.konten). L

Statische Methoden / Klassenmethoden

Methoden einer Klasse, die keine Werte der Instanzen nutzen, werden statische Methoden genannt. Sinnvollerweise werden Sie nur dann an die Klassen gebunden, wenn Sie den Klassenzustand nutzen oder ihr Anwendungsfall eng mit der Klasse verbunden ist.

Im obigen Beispiel wurde eine Liste erzeugt, die alle Instanzen der Klassen hält. Die statische Methode konten_uebersicht() gibt einen Überblick über die einzelnen Instanzen. Im Gegensatz zu Methoden, die an Objektinstanzen gekoppelt sind, wird hier nicht die Referenz self als erstes Attribut erwartet:

Im UML-Klassendiagramm werden die statischen Methoden und Attribute unterstrichen:

UML-Klassendiagramm für die Kunde mit dem statischen Attribut konten und der statischen Methode konten_uebersicht()
UML-Klassendiagramm für die Kunde mit dem statischen Attribut konten und der statischen Methode konten_uebersicht()

Eine komplette Beispielklasse mit statischen Membern könnte als UML-Klassendiagramm etwa so aussehen:

UML-Klassendiagramm für die Kunde mit dem statischen Attribut konten und der statischen Methode konten_uebersicht()
UML-Klassendiagramm für die Kunde mit dem statischen Attribut konten und der statischen Methode konten_uebersicht()

Exkurs: Type-Annotations für eigene Klassen

Zur guten Dokumentation von Python-Code gehört auch, dass dieser mit Datentypen annotiert wird, wo eine solche Information zum Verständnis des Codes hilfreich ist. Bei Type-Annotations handelt es sich nicht um funktionalen Code, der ausgeführt wird oder eine typsicherheit generiert. Vielmehr handelt es sich um eine Art Kommentar, die zwar von Lintern oder Testumgebungen (pytest, pep8) ausgewertet werden kann.

Für Objektsammlungen (z.B. List) oder eigene Klassen sind hier Imports nötig (aus typing, für eigene Klassen z.B. ClassVar), damit die Type-Annotations korrekt erkannt werden.

Bei Klassen wird das beispielsweise so umgesetzt:

Im Einzelnen:

  • Klassenvariablen werden mit “ClassVar” annotiert.

  • Die Typeannotation von Attributen erfolgt ohne vorangestelltes self an der Stelle, an der Klassenvariablen genannt werden.

  • Die eigene neue Klasse kann nicht mit dem Typen selbst annotiert werden (meinKonto: Konto), weil der zu diesem Zeitpunkt noch nicht verfügbar ist. Stattdessen wird einfach die Zeichenkette des Klassennamens zur Annotation genutzt.

Listing

Der Beispielcode ergibt sich mit den im obigen UML-Klassendiagramm modellierten Membern und Type-Annotations zu:

from typing import List, ClassVar
from datetime import datetime


class Konto:
    konto_stand: float
    inhaber_name: str
    zinssatz: float
    kontoauszug: List[str]
    kontoauszug_nr: int
    iban: str
    konten: ClassVar[List['Konto']] = []

    def __init__(self, inhaber_name: str, zinssatz: float) -> None:
        self.konto_stand = 0
        self.inhaber_name = inhaber_name
        self.zinssatz = zinssatz
        self.kontoauszug_nr = 0
        self.kontoauszug = []
        self.kontoauszug.append(self.kontoauszug_zeile("Kontoeröffnung von " + self.inhaber_name, 0))
        self.iban = ""
        Konto.konten.append(self)

    def einzahlen(self, betrag: float) -> None:
        self.konto_stand += betrag
        self.kontoauszug_zeile("Einzahlung", betrag)

    def auszahlen(self, betrag: float) -> None:
        self.konto_stand -= betrag
        self.kontoauszug_zeile("Auszahlung", betrag)

    def kontoauszug_zeile(self, betreff:str, betrag:float) -> str:
        zeit = datetime.now()
        zeit = zeit.strftime("%d/%m/%Y %H:%M:%S")
        self.kontoauszug_nr = self.kontoauszug_nr + 1
        return zeit + " KtStand: %8.2f " % self.konto_stand + " Konto von " + self.inhaber_name + ", Auszug " + str(self.kontoauszug_nr) + ", Betrag: " + str(self.konto_stand)

    def verzinsen(self) -> None:
        self.konto_stand +=  self.konto_stand * self.zinssatz

    def __str__(self) -> str:
        return "Konto "+str(self.iban)+ " von "+self.inhaber_name+" Kontostand: "+str(self.konto_stand)

    def konten_uebersicht() -> str:
        kontouebersicht = ""
        for konto in Konto.konten:
            kontouebersicht += str(konto)+"\n"
        return kontouebersicht


mein_konto = Konto("Dagobert Duck", 1.5)
sein_konto = Konto("Richie Rich", 3)

print(Konto.konten_uebersicht())

Welche Member (Attribute, Methoden) bietet die Klasse object und wofür sind sie zuständig?

In Python erben alle Klassen von der Klasse object. Diese bietet eine Reihe von Methoden, die wir nutzen (und überschreiben) können.

Generell hilft uns dir(), um die Member einer Klasse ausgeben zu lassen (Pythonshell):

Infos zu den einzelnen Membern können wir aufrufen mit (Pythonshell):

Eine Kurzübersicht findet sich in folgendem UML-Klassen-Diagramm:

UML-Klassendiagramm für Sets
UML-Klassendiagramm für Sets

Weitere Literatur zu object


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: Python OOP: Statische Member und Type-Annotation” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/python_oop_static veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/python-basics/erste-schritte-mit-python. Stand: 02.03.2024.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: