Klassen in Python: objektorientierte Programmierung

Lerne, eigene Klassen in Python zu schreiben. Definiere eine Klasse mit Konstruktor und Attributen, erstelle daraus Objekte und gib ihnen Methoden, die ihre Daten sicher verwenden und verändern. Sorge mithilfe von Spezialmethoden für lesbare Ausgaben und dafür, dass sich Objekte mit ==, beim Sortieren und mit + vergleichen oder kombinieren lassen. Erstelle Programme, in denen Objekte andere Objekte enthalten und aufrufen, und beurteile, wann eine Klasse ein Programm übersichtlicher macht als Funktionen und Wörterbücher.

AnfängerEinheit 10 von 10 in Kurs: Python-Programmierung – Schleifen, Funktionen, Listen und Dateien

Was du lernst

  1. Erkenne, dass jeder Python-Wert ein Objekt mit eigenen Daten und Methoden ist, und schreibe dann eine eigene Klasse und erstelle daraus Objekte.
    • Objekte erkennen, die du bereits verwendest
      Beschreibe Zeichenketten, Listen und Wörterbücher als Objekte, die einen Datentyp haben, Daten enthalten und Methoden anbieten, die du mit Punktnotation aufrufst.
    • Eine Klasse definieren und Instanzen erstellen
      Schreibe eine class-Anweisung, erstelle daraus mehrere getrennte Objekte und setze und lies ihre Attribute mit Punktnotation.
  2. Gib jedem neuen Objekt mit einem Konstruktor die benötigten Attribute, wähle zwischen Instanz- und Klassenattributen und verhindere, dass ungültige Objekte entstehen.
    • Einen Konstruktor mit __init__ und self schreiben
      Definiere __init__ so, dass jedes neue Objekt mit eigenen Attributen beginnt, die aus den Argumenten übernommen oder auf Anfangswerte gesetzt werden.
    • Zwischen Instanzattributen und Klassenattributen wählen
      Entscheide, ob ein Wert zu jedem einzelnen Objekt oder zur Klasse als Ganzes gehört, und sage voraus, wie Python die beiden Arten findet und verändert.
    • Objekte von Anfang an gültig halten
      Prüfe die Argumente eines Konstruktors, löse bei falschen Werten eine klare Ausnahme aus und halte die Regeln ein, die ein Objekt sinnvoll machen.
  3. Schreibe Methoden, die die Daten eines Objekts verwenden und verändern, und schütze diese Daten vor Änderungen, die das Objekt ungültig machen würden.
    • Instanzmethoden definieren und aufrufen
      Schreibe Methoden, die mit self arbeiten, rufe sie auf Objekten auf und gib Ergebnisse zurück, statt sie auszugeben.
    • Den Zustand eines Objekts mit Methoden ändern
      Schreibe Methoden, die Attribute aktualisieren und dabei das Objekt gültig halten, und sage voraus, wann eine Änderung über andere Namen für dasselbe Objekt sichtbar ist.
    • Attribute mit Namenskonventionen und Properties schützen
      Kennzeichne Attribute mit einem Unterstrich als intern und verwende Properties, um neue Werte zu prüfen oder stets aktuelle Werte zu berechnen.
  4. Schreibe Spezialmethoden, mit denen deine Objekte lesbaren Text anzeigen, sich mit == und < vergleichen lassen und mit Operatoren und eingebauten Funktionen funktionieren.
    • Objekten lesbare Zeichenkettendarstellungen geben
      Schreibe __str__ und __repr__ so, dass Objekte beim Ausgeben, Untersuchen oder Speichern in einer Liste nützlichen Text anzeigen.
    • Objekte mit Operatoren vergleichen und kombinieren
      Definiere __eq__, __lt__, __add__ und __len__, damit deine Objekte mit ==, beim Sortieren, mit + und mit len() funktionieren, und entscheide, wann ein Operator klarer ist als eine benannte Methode.
  5. Kombiniere Objekte so, dass jedes seine eigenen Daten verarbeitet, verfolge Programme, in denen Objekte einander aufrufen, und entscheide, wann eine Klasse ein Programm übersichtlicher macht.
    • Objekte erstellen, die andere Objekte enthalten
      Speichere Objekte als Attribute oder in Listen innerhalb eines anderen Objekts und schreibe Methoden, die mit der gesamten Sammlung arbeiten.
    • Objekte über Methoden miteinander interagieren lassen
      Übergib Objekte an Methoden und Funktionen, gib neue Objekte zurück und verfolge ein kurzes Programm, in dem mehrere Objekte zusammenarbeiten.
    • Entscheiden, wann eine Klasse ein Programm übersichtlicher macht
      Beurteile, wann es hilft, Daten und Verhalten in einer Klasse zu bündeln, plane eine kleine Klasse anhand einer Beschreibung und schreibe Code mit Wörterbüchern als Klasse um.

Klassen in Python einfach erklärt

5 Kapitel

1

Objekte verstehen und deine erste Klasse definieren

Objekte kommen bereits in jedem Python-Programm vor, das du schreibst: Eine Zeichenkette hat Methoden, eine Liste verändert ihren Inhalt und ein Wörterbuch liefert Werte beim Nachschlagen. Wenn du diese vertrauten Operationen als Verhalten von Objekten verstehst, hast du einen Ausgangspunkt für eigene Klassen. Lerne, wie Datentypen, Identität und gemeinsam genutzte Referenzen ein Programm beeinflussen. Definiere dann eine kleine Klasse und gib einzelnen Instanzen eigene Attribute.

1.1 Objekte erkennen, die du bereits verwendest

Du hast bereits Objekte verwendet, wann immer du mit einer Zahl, Zeichenkette, Liste oder einem Wörterbuch gearbeitet hast. Ein Objekt hat einen Datentyp, einen Wert oder Zustand und Operationen, die es unterstützt. Sogar Funktionen und None sind Objekte. Mit einer eigenen Klasse erweiterst du dieses vertraute System.

Datentyp und Methoden eines Objekts finden

type("hello") gibt <class 'str'> zurück; type([1, 2]) gibt <class 'list'> zurück. Die Wörter Datentyp und Klasse beschreiben hier dieselbe Rolle. isinstance(3.5, float) ist True, während isinstance("3.5", float) gleich False ist: Der zweite Wert ist Text, auch wenn er wie eine Zahl aussieht.

Eine Methode ist eine Funktion, die ein Datentyp bereitstellt. In "ada lovelace".title() ist die Zeichenkette vor dem Punkt das Objekt, title die Methode und die Klammern rufen sie auf. Das Ergebnis ist "Ada Lovelace". dir(value) listet die Namen auf, die ein Objekt anbietet; Namen wie __len__ sind Spezialmethoden, die Objekte mit Python-Operationen wie len(value) verbinden.

Ergebnis und ursprüngliches Objekt verfolgen

Ein Methodenaufruf kann ein Ergebnis zurückgeben, ein Objekt verändern oder beides tun. Prüfe das Verhalten der Methode, bevor du entscheidest, was du zuweist.

word = "level"
print(word.count("l"))  # 2
print(word.upper())     # LEVEL
print(word)             # level

nums = [3, 1, 2]
result = nums.sort()
print(nums)             # [1, 2, 3]
print(result)           # None

Zeichenketten sind unveränderlich: Ihr Inhalt kann sich nicht ändern. upper() gibt eine andere Zeichenkette zurück, sodass word seinen ursprünglichen Wert behält. Um das großgeschriebene Ergebnis unter diesem Namen zu speichern, schreibe word = word.upper().

Listen sind veränderlich. sort() verändert die Liste direkt und gibt None zurück. Mit nums = nums.sort() geht die in nums gespeicherte Listenreferenz verloren und None wird zugewiesen. Verwende nums.sort() in einer eigenen Zeile oder nums = sorted(nums), um eine neue sortierte Liste zu erhalten. Bei einem Wörterbuch gibt {"a": 1}.get("b", 0) den Wert 0 zurück, weil der gesuchte Schlüssel fehlt.

Auch Klammern sind wichtig. word.upper ist ein Methodenobjekt; word.upper() führt es aus. Viele Objekte können dasselbe Verhalten anbieten: "cat".upper() und "dog".upper() verwenden dieselbe Art von Methode mit unterschiedlichen Zeichenkettendaten.

Gleichheit und Identität unterscheiden

Gleichheit fragt, ob Werte übereinstimmen. Identität fragt, ob sich zwei Namen auf ein Objekt beziehen.

a = [1, 2]
b = [1, 2]
c = a
print(a == b)  # True
print(a is b)  # False
print(c is a)  # True
c.append(3)
print(a)       # [1, 2, 3]
print(b)       # [1, 2]

a und b haben anfangs gleiche Inhalte, sind aber separate Listen. c = a erstellt einen Alias, einen weiteren Namen für dieselbe Liste. Das Anhängen über c verändert das Objekt, auf das sich auch a bezieht. Die separate Liste, auf die b verweist, ändert sich nicht. Zeichne beim Nachvollziehen eines Programms einen Kasten pro Objekt und einen Pfeil von jedem Namen zu seinem Kasten.

Wichtige Erkenntnisse

  • Jeder Python-Wert ist ein Objekt mit einem Datentyp, einem Zustand und unterstützten Operationen.
  • Rufe eine Methode mit Klammern auf; eine Methodenreferenz allein führt sie nicht aus.
  • Prüfe, ob eine Methode einen neuen Wert zurückgibt oder das vorhandene Objekt verändert.
  • == vergleicht Werte; is vergleicht die Identität.
  • Durch eine Zuweisung können zwei Namen auf dasselbe veränderliche Objekt verweisen.

1.2 Eine Klasse definieren und Instanzen erstellen

Eine Klasse definiert einen Datentyp, den du in deinem eigenen Programm verwenden kannst. Jedes daraus erstellte Objekt ist eine Instanz. Eine Klasse beschreibt die Art des Objekts; Instanzen enthalten die Daten einzelner Objekte. Ein leeres Formular und seine ausgefüllten Kopien sind ein hilfreicher Vergleich.

Eine Klasse schreiben und aufrufen

Eine class-Anweisung besteht aus dem Schlüsselwort class, einem Namen, einem Doppelpunkt und einem eingerückten Körper. pass stellt einen leeren Körper bereit, während du die Struktur ausprobierst.

class Book:
    pass

b1 = Book()
b2 = Book()
print(b1 is b2)           # False
print(isinstance(b1, Book))  # True

Jeder Aufruf von Book() erstellt eine separate Instanz. In einem Skript zeigt type(b1) den Wert <class '__main__.Book'>. Die class-Anweisung muss ausgeführt werden, bevor Code versucht, Book zu verwenden. Du kannst eine Klasse auch in einem Modul definieren, sie mit from library import Book importieren und dann im aufrufenden Programm Instanzen erstellen.

Beachte die Namenskonventionen von Python: Book, BankAccount und ShoppingCart verwenden CapWords, wobei jedes Wort mit einem Großbuchstaben beginnt. Variablen und Methoden verwenden kleingeschriebene Wörter, die durch Unterstriche getrennt sind, etwa book_count und add_item. Verwende für jede Einrückungsebene vier Leerzeichen.

Daten auf jeder Instanz speichern

Ein Attribut ist ein benannter Wert, auf den du mit einem Punkt zugreifst. Eine Zuweisung an ein Attribut speichert den Wert; durch Lesen desselben Namens rufst du ihn ab.

b1.title = "Dune"
b2.title = "Emma"
b1.pages = 412
print(b1.title)  # Dune
print(b2.title)  # Emma
print(b1.pages)  # 412

Die Daten gehören zur ausgewählten Instanz. Wenn du b1 ein Attribut pages gibst, erhält b2 keines. Das Lesen von b2.pages löst nun AttributeError aus, weil dieses Objekt kein Attribut namens pages hat.

Zuweisungen können neue Namen erstellen, ohne deine Absicht zu prüfen. Nach b1.titel = "X" enthält das ursprüngliche b1.title weiterhin "Dune"; das Objekt hat ein zweites Attribut mit einem falsch geschriebenen Namen erhalten. Wenn sich ein Wert scheinbar nicht ändert, vergleiche die Schreibweise bei der Zuweisung und beim Lesen.

Klasse und Instanzen unterscheiden
AusdruckBedeutung
BookDas Klassenobjekt, das den Datentyp definiert
Book()Ein Aufruf, der eine Instanz erstellt
b1.titleDer auf diesem Buch gespeicherte Titel
Book.titleEin Attribut, das auf der Klasse selbst angefragt wird

b = Book gibt der Klasse einen weiteren Namen. Es erstellt kein Buch. Wurden Titel nur auf Instanzen gesetzt, löst die Anfrage nach Book.title einen AttributeError aus; es gibt keinen einzelnen Titel, den alle Objekte dieses Datentyps teilen.

Jedem Objekt einen verlässlichen Anfang geben

Attribute von außen zu setzen ist möglich, verteilt die Einrichtung aber über das Programm. Ein Buch könnte einen Titel und eine Seitenzahl erhalten, ein anderes nur einen Titel. Späterer Code kann nicht sicher voraussetzen, dass beide pages haben.

Eine Einrichtungsmethode namens __init__ platziert die anfänglichen Zuweisungen innerhalb der Klasse. Jeder Aufruf zur Erstellung folgt dann demselben Einrichtungsprozess. Die Klasse kann einen Titel verlangen und andere Attribute mit sinnvollen Anfangswerten erstellen, sodass sich der aufrufende Code keine separate Folge von Zuweisungen merken muss.

Wichtige Erkenntnisse

  • Eine Klasse definiert einen Datentyp; eine Instanz ist ein daraus erstelltes Objekt.
  • Erstelle mit ClassName() eine Instanz und greife mit Punktnotation auf ihre Attribute zu.
  • Jede Instanz kann unter denselben Attributnamen andere Daten enthalten.
  • Ein fehlendes Attribut löst AttributeError aus; eine falsch geschriebene Zuweisung kann ein neues Attribut erstellen.
2

Objekte mit Konstruktoren und Attributen einrichten

Ein Objekt benötigt einen verlässlichen Anfangszustand, bevor seine Methoden sinnvolle Arbeit leisten können. Die Initialisierung verbindet die Argumente eines Klassenaufrufs mit Attributen, die auf der neuen Instanz gespeichert werden. Wähle, welche Werte zu einem einzelnen Objekt und welche zur Klasse gehören, und validiere dann Eingaben, bevor du sie übernimmst. Wenn du die Attributsuche und Fehler bei der Einrichtung nachvollziehst, erkennst du versehentlich gemeinsam genutzte und fehlende Daten leichter.

2.1 Einen Konstruktor mit __init__ und self schreiben

Jedes neu erstellte Konto benötigt einen Inhaber und einen Anfangskontostand. Wenn diese Einrichtung in __init__ steht, erhält jedes Objekt die Attribute, die spätere Methoden erwarten. Python erstellt zuerst die Instanz und ruft dann __init__ auf, um sie zu initialisieren.

Argumente mit Attributen verbinden
class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance
        self.transactions = []

acct = BankAccount("Maya", 50)
other = BankAccount("Leo")

Beim ersten Aufruf übergibt Python das neue Konto als self, "Maya" als owner und 50 als balance. Durch die Zuweisungen wird acct.owner gleich "Maya" und acct.balance gleich 50. Der zweite Aufruf verwendet den Standardwert für den Kontostand, sodass other.balance gleich 0 ist.

self ist der Parameter, der das aktuelle Objekt erhält. Es ist eine Konvention und kein Python-Schlüsselwort. Verwende diesen Namen, damit Lesende das Objekt sofort erkennen. Der aufrufende Code lässt ihn weg: BankAccount("Maya", 50) übergibt zwei Argumente, nicht drei.

Lokale Namen und gespeicherte Daten unterscheiden

In self.owner = owner ist der Name rechts ein lokaler Parameter. Der Name links ist ein Attribut, das auf dem Objekt gespeichert wird. Nach der Initialisierung können andere Methoden self.owner weiterhin verwenden.

balance = balance weist nur dem lokalen Namen erneut einen Wert zu. Es erstellt kein Attribut, sodass das spätere Lesen von acct.balance scheitert. Setze self. vor jedes Attribut, das Teil des Objekts bleiben soll.

Plane die Initialisierung, indem du auflistest, was jede Instanz benötigt. Erforderliche Werte werden zu Parametern nach self; optionale Werte können Standardwerte haben. Werte, die immer gleich beginnen, können im Körper zugewiesen werden, etwa self.visits = 0. Eine mit self.transactions = [] erstellte Liste wird bei jedem Aufruf neu angelegt.

Eine gemeinsam genutzte Standardliste vermeiden

Ein Standardargument wird ausgewertet, wenn Python die Methode definiert. Bei def __init__(self, items=[]) erhalten Aufrufe, die items weglassen, dieselbe Liste. Speichert der Initialisierer diese Liste direkt, ändert eine Änderung an den Elementen eines Objekts auch die Elemente, die ein anderes sieht.

Verwende None als Standardwert und erstelle bei jedem Aufruf eine neue Liste:

class Cart:
    def __init__(self, items=None):
        self.items = [] if items is None else list(items)

a = Cart()
b = Cart()
a.items.append("pen")
print(b.items)  # []

list(items) erstellt auch dann eine neue äußere Liste, wenn der aufrufende Code eine Liste übergibt. Die Objekte in dieser Liste werden weiterhin über gemeinsame Referenzen genutzt; beim Erstellen der Liste wird nicht jedes Element neu erstellt.

Fehler bei der Einrichtung lesen

BankAccount() fehlt das erforderliche Argument owner und löst TypeError aus. Vergleiche den Aufruf mit den Parametern nach self.

Die Schreibweise __init__ hat auf jeder Seite zwei Unterstriche. _init_ ist ein gewöhnlicher Methodenname und führt diese Einrichtung nicht automatisch aus. __init__ muss None zurückgeben, also lass normalerweise eine return-Anweisung weg. Die Rückgabe eines Kontostands löst TypeError aus; der Klassenaufruf selbst liefert dem aufrufenden Code die neue Instanz.

Wichtige Erkenntnisse

  • __init__ initialisiert die Instanz, nachdem Python sie erstellt hat.
  • Python übergibt self; der aufrufende Code übergibt die übrigen Argumente.
  • self.name = name speichert einen Parameter als Instanzattribut.
  • Erstelle Listen für einzelne Instanzen bei der Initialisierung; verwende None statt eines veränderlichen Standardwerts.
  • __init__ muss None zurückgeben.

2.2 Zwischen Instanzattributen und Klassenattributen wählen

Einige Werte beschreiben ein einzelnes Objekt, andere den Datentyp als Ganzes. Die Größe einer Pizza gehört zu dieser Pizza. Eine Obergrenze für Beläge oder ein Zähler für erstellte Pizzen kann zur Klasse gehören. Wo eine Zuweisung erfolgt, bestimmt, welche Art von Attribut sie erstellt.

Den Wert an der richtigen Stelle ablegen
class Pizza:
    MAX_TOPPINGS = 5
    count = 0

    def __init__(self, size):
        self.size = size
        self.toppings = []
        Pizza.count += 1

p1 = Pizza("large")
p2 = Pizza("small")

size und toppings sind Instanzattribute, die auf self gesetzt werden. Jede Pizza hat ihre eigenen Werte. MAX_TOPPINGS und count sind Klassenattribute, die im Klassenkörper außerhalb einer Methode zugewiesen werden. Großbuchstaben kennzeichnen einen Wert, der als Konstante gedacht ist; sie verhindern keine erneute Zuweisung.

Nach diesen Aufrufen ist Pizza.count gleich 2. Jeder Initialisierer aktualisiert dasselbe Klassenattribut. p1.size ist "large", während p2.size gleich "small" ist.

Attributsuche und Verdeckung nachvollziehen

Beim Lesen von p1.MAX_TOPPINGS wird bei gewöhnlichen Datenattributen wie diesen zuerst die Instanz und dann die Klasse geprüft. Da auf p1 kein Wert gespeichert ist, findet Python Pizza.MAX_TOPPINGS, also 5.

Eine Zuweisung über eine Instanz wirkt anders:

p1.MAX_TOPPINGS = 8
Pizza.MAX_TOPPINGS = 6
print(p1.MAX_TOPPINGS)     # 8
print(p2.MAX_TOPPINGS)     # 6
print(Pizza.MAX_TOPPINGS)  # 6

Die erste Zeile erstellt ein Instanzattribut auf p1. Es verdeckt den Klassenwert für dieses Objekt. Eine spätere Änderung des Klassenwerts erreicht p2, das den Wert weiterhin von der Klasse liest, ersetzt aber nicht den eigenen Wert von p1.

ZuweisungWas sich ändert
self.size = sizeDaten auf der aktuellen Instanz
Pizza.count += 1Der gemeinsam genutzte Klassenzähler
p1.MAX_TOPPINGS = 8Ein Instanzwert, der den Klassenwert verdeckt
Auf zwei Arten unbeabsichtigter gemeinsamer Nutzung achten

Würde der Initialisierer self.count += 1 verwenden, würde Python die 0 der Klasse lesen, eins addieren und ein Instanzattribut speichern. Jede neue Pizza würde einen eigenen Wert 1 für count erhalten, während Pizza.count bei 0 bliebe. Nenne die Klasse, wenn du einen klassenweiten Zähler aktualisierst.

Eine Liste im Klassenkörper verursacht ein anderes Problem. Bei toppings = [] finden alle Instanzen ohne separates Belagattribut dieselbe Liste. p1.toppings.append("olives") verändert diese gemeinsam genutzte Liste; es weist kein neues Instanzattribut zu. Setze self.toppings = [] in __init__, wenn jede Pizza ihren eigenen Belag benötigt.

Eigene Daten eines Objekts untersuchen

Für das ursprüngliche p2 ergibt vars(p2) den Wert {'size': 'small', 'toppings': []}. Die Klassenwerte fehlen, weil sie auf Pizza liegen. Das ist bei der Fehlersuche nach einer überraschenden Attributsuche nützlich: Prüfe, ob die Instanz einen eigenen Wert hat, und untersuche dann den Klassenwert. Eine gemeinsame Einstellung gehört auf die Klasse; ein Name, eine Größe, ein Kontostand oder eine persönliche Sammlung gehört auf die Instanz.

Wichtige Erkenntnisse

  • Instanzattribute enthalten Daten für ein einzelnes Objekt; Klassenattribute enthalten gemeinsame Einstellungen oder klassenweite Daten.
  • Ein Datenattribut einer Instanz kann ein gleichnamiges Klassenattribut verdecken.
  • Aktualisiere einen gemeinsamen Zähler über den Klassennamen.
  • Eine Veränderung an einer Liste auf Klassenebene verändert die eine gemeinsam genutzte Liste.
  • vars(obj) zeigt die eigenen gespeicherten Attribute, nicht die Klassenattribute, die das Objekt finden kann.

2.3 Objekte von Anfang an gültig halten

Ein Objekt sollte in einem Zustand beginnen, den seine Methoden verwenden können. Ein Rechteck mit negativer Breite kann die beabsichtigte Form nicht darstellen. Eine Regel, die für jedes Objekt einer Klasse immer gelten muss, heißt Invariante. Die Validierung prüft diese Regeln, bevor Daten übernommen werden.

Vor dem Speichern prüfen
class Rectangle:
    def __init__(self, width, height):
        if width <= 0:
            raise ValueError("width must be positive")
        if height <= 0:
            raise ValueError("height must be positive")
        self.width = width
        self.height = height

Rectangle(3, 4) besteht beide Prüfungen und gibt ein initialisiertes Objekt zurück. Rectangle(-2, 4) löst bei der ersten Prüfung ValueError aus. Die späteren Zuweisungen werden nicht ausgeführt. Fängt das Programm diese Ausnahme nicht ab, stoppt die Ausführung an dieser Stelle.

Angenommen, r verweist bereits auf ein gültiges Rechteck. Bei r = Rectangle(-2, 4) scheitert der Aufruf rechts vor der Zuweisung. r behält seinen vorherigen Wert. Hatte r vor dem fehlgeschlagenen Aufruf keinen Wert, erstellt die Zuweisung auch keinen.

Eine hilfreiche Ausnahme wählen
AusnahmeBeschriebenes Problem
ValueErrorEine Eingabe zulässiger Art hat einen unzulässigen Wert
TypeErrorDie Eingabe hat für die Operation den falschen Datentyp

Eine negative Breite als Zahl ist ein Wertfehler. Text, der anstelle einer benötigten Zahl übergeben wird, ist ein Typfehler. Der Vergleich mit 0 löst in diesem Beispiel bei Text bereits TypeError aus. Eine Klasse kann einen Datentyp auch ausdrücklich mit isinstance prüfen, wenn sie eine klarere Meldung benötigt.

Schreibe Meldungen, die die Regel nennen, etwa "width must be positive". Bei einer Meldung, die nur "bad input" sagt, müssen die Aufrufenden raten, welcher Wert korrigiert werden muss.

Fehlerbehandlung dem aufrufenden Code überlassen
while True:
    try:
        width = float(input("Width: "))
        room = Rectangle(width, 3)
        break
    except ValueError as error:
        print("Try again:", error)

Die Eingabe abc scheitert bei float; die Eingabe -2 besteht die Umwandlung, scheitert aber in Rectangle. Beide lösen ValueError aus, sodass diese Schleife beide Fälle behandelt. Die Klasse gibt ihre Datenregel vor, während der aufrufende Code entscheidet, erneut zu fragen.

Eine Warnung innerhalb von __init__ auszugeben weist den Aufruf nicht zurück. Wird die Ausführung fortgesetzt, kann das Programm ein ungültiges Objekt erhalten und später bei dessen Verwendung scheitern. Das Auslösen einer Ausnahme stoppt die fehlgeschlagene Einrichtung dort, wo das Problem auftritt.

Daten gezielt bereinigen und die Regel einhalten

Eine dokumentierte Bereinigung kann nützlich sein. self.name = name.strip() entfernt Leerzeichen am Rand; validiere den bereinigten Namen, wenn leere Namen verboten sind. self.items = list(items) erstellt eine separate äußere Liste, sodass das Anhängen an die Liste des aufrufenden Codes nichts an diese Liste anhängt. Eine ungültige Breite in ihren Betrag zu ändern, würde die Absicht des aufrufenden Codes ändern und benötigt daher eine ausdrückliche Entwurfsregel.

Die Prüfungen bei der Initialisierung laufen zum Zeitpunkt der Erstellung. Eine einfache Zuweisung wie r.width = -5 umgeht sie später trotzdem. Methoden, die eine Breite ändern, müssen sie erneut prüfen. Eine Property kann eine Prüfung direkt bei der Attributzuweisung vornehmen, sodass dieselbe Regel bei der Einrichtung und bei späteren Aktualisierungen ausgeführt wird.

Wichtige Erkenntnisse

  • Eine Invariante ist eine Regel, die ein gültiger Objektzustand erfüllen muss.
  • Validiere Daten vor der Übernahme und löse bei einem Fehler eine klare Ausnahme aus.
  • Ein fehlgeschlagener Erstellungsaufruf weist dem Namen des aufrufenden Codes kein neues Objekt zu.
  • Prüfungen im Konstruktor müssen auch durch spätere Methoden oder Properties unterstützt werden, die den Zustand ändern.
3

Objekten mit Instanzmethoden Verhalten geben

Methoden machen gespeicherte Daten zu nützlichem Verhalten. Ein Rechteck kann seine Fläche berechnen und ein Konto seinen Kontostand aktualisieren und dabei eine Transaktion erfassen. Verfolge, wie Python das Empfängerobjekt an jede Methode übergibt, und unterscheide dann ein zurückgegebenes Ergebnis von einer Zustandsänderung. Properties ermöglichen einer Klasse, einen lesbaren Attributzugriff beizubehalten und zugleich Zuweisungen zu prüfen oder Werte bei Bedarf zu berechnen.

3.1 Instanzmethoden definieren und aufrufen

Eine Instanzmethode ist eine innerhalb einer Klasse definierte Funktion, die mit dem als self übergebenen Objekt arbeitet. Das Objekt liefert seine gespeicherten Daten; zusätzliche Parameter liefern weitere Informationen, die für die Aktion benötigt werden.

Attribute über self lesen

Füge diese Methoden innerhalb der validierten Klasse Rectangle auf derselben Einrückungsebene wie __init__ hinzu:

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

    def is_square(self):
        return self.width == self.height

Bei r = Rectangle(3, 4) gibt r.area() den Wert 12, r.perimeter() den Wert 14 und r.is_square() den Wert False zurück. Jede Methode liest die Attribute desselben Objekts. Ein zweites Rechteck verwendet dieselben Methodendefinitionen mit seiner eigenen Breite und Höhe.

Innerhalb einer Methode bezeichnet self.width ein Attribut. Ein alleinstehendes width bezeichnet eine lokale oder eine andere zugängliche Variable; Python sucht dafür nicht automatisch auf dem aktuellen Objekt. Existiert keine solche Variable, löst return width * height einen NameError aus. Mit self. machst du ausdrücklich kenntlich, zu welchem Objekt die Daten gehören.

Den Aufruf verfolgen

Für diese Klasse funktioniert r.area() wie Rectangle.area(r). Python findet die Funktion auf der Klasse und übergibt r als erstes Argument. Eine Methodenreferenz wie r.area ist eine gebundene Methode: Sie merkt sich die Funktion und dieses Rechteck. Mit () führst du den Aufruf aus.

Ist eine Methode als def resize(self, factor) definiert, rufe sie als r.resize(2) auf. r belegt self und 2 belegt factor. Du übergibst r nicht noch einmal. Wird eine Instanzmethode versehentlich als def area(): geschrieben, löst ein Aufruf auf r einen TypeError aus, weil Python das Objekt trotzdem an eine Funktion übergibt, die keine Argumente annimmt.

Eine Methode kann über self eine andere verwenden:

    def double_area(self):
        return self.area() * 2

Hier berechnet self.area() die Fläche desselben Rechtecks. Ohne self. würde eine separate Funktion namens area gesucht, nicht die Methode des Objekts.

Ergebnisse an den aufrufenden Code zurückgeben

Eine Berechnungsmethode sollte normalerweise ihr Ergebnis zurückgeben. Die Rückgabe liefert dem aufrufenden Code einen Wert zum Speichern, Kombinieren, Prüfen oder Anzeigen:

r1 = Rectangle(3, 4)
r2 = Rectangle(2, 5)
total = r1.area() + r2.area()
print(total)  # 22

Würde area seine Antwort nur ausgeben, gäbe jeder Aufruf None zurück. Die Addition würde dann mit TypeError scheitern, obwohl zwei Zahlen auf dem Bildschirm erschienen wären. Eine Ausgabe ist eine Aktion; eine Rückgabe liefert einen Wert an den Ausdruck, der den Aufruf enthält.

Verwende Methodennamen, die die Aufgabe zeigen. deposit und resize benennen Aktionen; is_square und has_room deuten auf boolesche Prüfungen hin. Für Daten, die bereits auf ihrem Objekt gespeichert sind, benötigt eine Methode keine Parameter. Für neue Eingaben, etwa einen Faktor zur Größenänderung oder einen Einzahlungsbetrag, benötigt sie Parameter.

Wichtige Erkenntnisse

  • Setze self an die erste Stelle einer Instanzmethode; Python übergibt das Empfängerobjekt.
  • Lies Attribute und rufe andere Methoden über self. auf.
  • Klammern führen eine gebundene Methode aus.
  • Gib berechnete Werte zurück, damit der aufrufende Code sie kombinieren, prüfen oder anzeigen kann.

3.2 Den Zustand eines Objekts mit Methoden ändern

Der Zustand eines Objekts besteht aus den aktuellen Werten seiner Attribute. Eine Zugriffsmethode gibt Auskunft über diesen Zustand. Eine Änderungsmethode verändert ihn. Eine nützliche Änderungsmethode prüft ihre Eingaben und hält alle zusammengehörenden Attribute aktuell, sodass der aufrufende Code nicht mehrere Aktualisierungen koordinieren muss.

Zuerst die gesamte Änderung validieren

Füge diese Methoden in die Klasse BankAccount mit ihrem Inhaber, Kontostand und ihrer Transaktionsliste ein:

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("deposit must be positive")
        self.balance += amount
        self.transactions.append(("deposit", amount))

    def withdraw(self, amount):
        if amount <= 0:
            raise ValueError("withdrawal must be positive")
        if amount > self.balance:
            raise ValueError("insufficient funds")
        self.balance -= amount
        self.transactions.append(("withdraw", amount))

Eine Einzahlung ändert den Kontostand und erfasst den Vorgang. Eine Auszahlung prüft vor dem Abziehen sowohl das Vorzeichen des Betrags als auch den verfügbaren Kontostand. Diese Prüfungen verhindern, dass eine abgelehnte Auszahlung den Kontostand oder dessen Verlauf ändert.

Ausgehend von BankAccount("Maya", 50) ergibt eine Einzahlung von 25 den Wert 75 und eine Auszahlung von 30 den Wert 45. Ein späterer Versuch, 100 abzuheben, löst ValueError aus; er belässt den Kontostand bei 45 und fügt keine Transaktion hinzu. Stünde die Subtraktion vor der Deckungsprüfung, würde sich der Zustand auch bei einem Fehlschlag ändern.

Eine Änderung von einem Rückgabewert unterscheiden

Diese Änderungsmethoden haben keine return-Anweisung und geben daher None zurück. Nach new_balance = acct.deposit(25) ist die Einzahlung erfolgt, aber new_balance ist None. Lies danach acct.balance, um den aktualisierten Wert zu erhalten.

Eine Klasse kann auch eine andere Art von Methode anbieten, die ein neues Objekt zurückgibt. resize deutet darauf hin, ein Rechteck zu verändern; resized kann für eine Methode gewählt werden, die ein neues Rechteck zurückgibt und das ursprüngliche unverändert lässt. Lies die Vereinbarung der Methode: Der Name hilft, aber ihre Definition bestimmt das Verhalten.

Gemeinsame Referenzen nachvollziehen
a = BankAccount("Maya", 50)
b = a
b.deposit(10)
print(a.balance)  # 60
print(a is b)     # True

Eine Zuweisung bindet einen Namen an ein Objekt; sie kopiert das Objekt nicht. Beide Namen führen zu dem Konto, dessen Kontostand sich geändert hat. Wird a an eine Funktion übergeben, erhält auch diese Zugriff auf das Objekt. Eine Funktion, die account.withdraw(5) aufruft, kann daher das Konto verändern, das der aufrufende Code sieht.

Für ein unabhängiges Konto mit demselben Inhaber und Kontostand erstelle BankAccount(a.owner, a.balance). Dieser Konstruktor liefert auch einen neuen, leeren Verlauf. Es ist ein neues Konto, keine vollständige Kopie des bisherigen Verlaufs.

copy.copy(a) erstellt ein neues äußeres Objekt, behält aber Referenzen auf dieselben inneren Objekte, einschließlich der Transaktionsliste. copy.deepcopy(a) kopiert auch verschachtelte Objekte. Wenn Unabhängigkeit wichtig ist, prüfe sowohl die Objekte innerhalb der Attribute als auch die äußere Instanz.

Eine direkte Zuweisung wie acct.balance = -500 umgeht die Prüfungen in den beiden Methoden. Konventionen für interne Attribute und Properties helfen, den vorgesehenen Weg für Aktualisierungen deutlich zu machen und die Validierung nahe an den Zustandsänderungen zu halten.

Wichtige Erkenntnisse

  • Prüfe eine angeforderte Änderung, bevor du Attribute aktualisierst.
  • Eine Änderungsmethode kann den Zustand ändern und dabei None zurückgeben.
  • Zuweisung und Argumentübergabe erhalten Referenzen auf dasselbe Objekt.
  • Eine flache Kopie kann weiterhin verschachtelte veränderliche Objekte gemeinsam nutzen.
  • Halte zusammengehörende Zustandsänderungen in der dafür verantwortlichen Methode zusammen.

3.3 Attribute mit Namenskonventionen und Properties schützen

Der aufrufende Code benötigt eine klare Möglichkeit, ein Objekt zu lesen und zu verändern. Kapselung hält die Datenregeln eines Objekts bei den Methoden, die sie verwalten. Python verwendet Konventionen und Properties, um diese Schnittstelle auszudrücken.

Interne Speicherung kennzeichnen

Ein führender Unterstrich in _balance kennzeichnet ein internes Attribut. Der aufrufende Code sollte die Methoden des Kontos verwenden, aber Python erlaubt weiterhin den direkten Zugriff. Es gibt kein Schlüsselwort private, das den Wert wegsperrt.

Ein Name wie __balance mit zwei führenden und ohne zwei abschließende Unterstriche löst die Namensumformung aus. Innerhalb von class Acc wird self.__balance unter _Acc__balance gespeichert. Außerhalb scheitert obj.__balance, aber obj._Acc__balance kann weiterhin funktionieren. Die Namensumformung verhindert Namenskonflikte; sie schützt keine vertraulichen Daten.

Eine Methode über Attributsyntax ausführen

Eine Property führt eine Methode aus, wenn ein Attribut gelesen wird. Die Zeile @property ist ein Dekorator: Sie ändert, wie Python die Methode bereitstellt. Eine Property ohne Setter erlaubt das Lesen, weist aber Zuweisungen zurück.

class Account:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self._balance = balance

    @property
    def balance(self):
        return self._balance

Lies nach acct = Account("Maya", 50) den Wert von acct.balance ohne Klammern. Die Zuweisung acct.balance = 10 löst AttributeError aus, weil diese Property keinen Setter hat. Eine Einzahlungsmethode innerhalb der Klasse könnte _balance nach ihren Prüfungen aktualisieren.

Zuweisungen mit einem Setter prüfen
class Student:
    def __init__(self, name, score):
        self.name = name
        self.score = score

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not 0 <= value <= 100:
            raise ValueError("score must be between 0 and 100")
        self._score = value

Getter und Setter haben denselben Namen score; der gespeicherte Wert verwendet _score. Bei der Erstellung führt self.score = score den Setter aus.

Bei s = Student("Ana", 88) speichert die Zuweisung s.score = 92 den Wert 92. Die Zuweisung s.score = -1 löst vor dem Speichern ValueError aus, sodass die Punktzahl bei 92 bleibt. Student("Ana", 105) scheitert bei der Initialisierung.

Innerhalb des Setters würde self.score = value den Setter erneut aufrufen. Das würde sich bis zum RecursionError wiederholen. Beim Getter besteht dasselbe Risiko, wenn er self.score zurückgibt. Verwende in beiden Körpern den separaten Speichernamen _score.

Werte beim Lesen berechnen

Eine Property kann einen Wert aus anderen Attributen berechnen:

    @property
    def area(self):
        return self.width * self.height

Innerhalb einer Rechteckklasse ermöglicht dies r.area. Bei Breite 3 und Höhe 4 ist der Wert 12. Änderst du die Breite auf 5, gibt das nächste Lesen 20 zurück. Würde eine Fläche bei der Initialisierung einmal gespeichert, bliebe nach einer Änderung der Breite ein alter Wert zurück.

Beginne mit einem einfachen Attribut, wenn eine einfache Speicherung den Bedarf erfüllt.

Wichtige Erkenntnisse

  • Ein führender Unterstrich kennzeichnet nach Konvention eine interne Speicherung; er sperrt den Zugriff nicht.
  • Die Namensumformung ändert einen Attributnamen, um Konflikte zu vermeiden.
  • Eine Property führt über Attributsyntax einen Getter aus.
  • Ein Setter kann die Initialisierung und spätere Zuweisungen an einer Stelle validieren.
  • Verwende ein separates speicherndes Attribut, um einen rekursiven Aufruf der Property zu vermeiden.
  • Eine berechnete Property leitet ihren Wert beim Lesen ab.
4

Spezialmethoden für lesbare Ausgaben und Vergleiche von Objekten verwenden

Ein nützliches Objekt sollte sich natürlich in gewöhnliche Python-Ausdrücke einfügen. Seine Spezialmethoden können lesbaren Text, Wertgleichheit, eine Ordnung, Rechenergebnisse oder eine Länge bereitstellen. Lerne, welche Methode Python in welcher Situation anfordert und was diese Methode zurückgeben muss. Achte besonders auf Darstellungen innerhalb von Containern, stabile Wörterbuchschlüssel und den Unterschied zwischen einer Operation und ihrer reflektierten Form.

4.1 Objekten lesbare Zeichenkettendarstellungen geben

Ein Objekt lässt sich leichter untersuchen, wenn es seine eigenen Daten beschreiben kann. Spezialmethoden ermöglichen Python, diese Beschreibung über vertraute Aktionen wie print, str und repr anzufordern. Ihre Namen beginnen und enden mit zwei Unterstrichen und werden oft Dunder-Namen genannt.

Text für zwei Zielgruppen wählen

__str__ liefert lesbaren Text für die Benutzer eines Programms. __repr__ liefert eine genaue Beschreibung für Programmierende. Beide geben Zeichenketten zurück; keine der beiden Methoden sollte ihr Ergebnis anstelle der Rückgabe ausgeben.

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"({self.x}, {self.y})"

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

p = Point(3, 4)
print(p)        # (3, 4)
print(repr(p))  # Point(3, 4)

str(p) gibt die Zeichenkette "(3, 4)" zurück. repr(p) gibt "Point(3, 4)" zurück. Wenn möglich, ähnelt eine Darstellung einem Klassenaufruf, der den Wert erneut erstellen würde. Sie bleibt dennoch Text: Der Aufruf von repr selbst erstellt keinen weiteren Punkt.

Ohne eigene Darstellung zeigt eine einfache Instanz typischerweise einen Klassennamen und eine adressähnliche Kennung. Das hilft, Objekte zu unterscheiden, zeigt aber nicht ihre nützlichen Daten. Du rufst diese Spezialmethoden selten direkt auf; definiere sie einmal und verwende die üblichen Ausgabeoperationen von Python.

Vorhersagen, was ein Container anzeigt
AusdruckAngeforderte Darstellung
print(p) oder str(p)__str__
repr(p)__repr__
f"{p}"Die übliche Zeichenkettendarstellung für diese Klasse
f"{p!r}"__repr__
print([p])Die Darstellung der Liste, die für ihr Element repr verwendet

Mit der obigen Klasse zeigt print([Point(3, 4), Point(0, 0)]) die Ausgabe [Point(3, 4), Point(0, 0)]. Die Liste verwendet die Darstellungen ihrer Elemente, obwohl jedes Element auch __str__ hat.

Definierst du nur __repr__, verwendet das standardmäßige __str__ diese Methode ebenfalls. Die alleinige Definition von __str__ ändert weder repr noch die Darstellung in Containern. Wenn du nur eine Darstellungsmethode hinzufügst, ist __repr__ daher in mehr Untersuchungssituationen hilfreich.

Zeichenkettenfelder eindeutig machen

Für ein Buch, das bereits title, author und year speichert, liefern diese Methoden unterschiedliche nützliche Ansichten:

    def __str__(self):
        return f"{self.title} by {self.author} ({self.year})"

    def __repr__(self):
        return f"Book({self.title!r}, {self.author!r}, {self.year})"

Für das Buch mit dem Titel "Dune", dem Autor "Frank Herbert" und dem Jahr 1965 ergibt die erste Methode "Dune by Frank Herbert (1965)". Die zweite ergibt "Book('Dune', 'Frank Herbert', 1965)". !r fordert die Darstellungen der Zeichenkettenfelder einschließlich Anführungszeichen an.

Ein Körper, der nur print(self.x) enthält, gibt None zurück, sodass str(p) mit TypeError scheitert. Auch die Rückgabe einer ganzen Zahl scheitert. Erstelle den benötigten Text und gib dann diese Zeichenkette zurück.

Wichtige Erkenntnisse

  • __str__ liefert Text für Benutzer; __repr__ liefert eine nützliche Darstellung für Programmierende.
  • Container zeigen ihre Elemente mit repr an.
  • __repr__ kann die standardmäßige Zeichenkettendarstellung liefern; __str__ ersetzt repr nicht.
  • Beide Methoden müssen Zeichenketten zurückgeben.
  • Verwende !r in einem f-String, um Darstellungen von Zeichenkettenfeldern mit Anführungszeichen anzuzeigen.

4.2 Objekte mit Operatoren vergleichen und kombinieren

Spezialmethoden verbinden eine Klasse mit Operatoren und eingebauten Funktionen. Definiere nur Operationen, deren Bedeutung für den jeweiligen Datentyp klar ist: Das Addieren von Vektoren ist verständlich; einen Spieler zu einem Team hinzuzufügen ist mit team.add_player(player) klarer.

Werte vergleichen und Hashwerte sicher halten

Zwei separate einfache Instanzen gelten standardmäßig als ungleich. Ergänze eine Punktklasse um Wertgleichheit:

    def __eq__(self, other):
        if not isinstance(other, Point):
            return NotImplemented
        return self.x == other.x and self.y == other.y

Nun gelten zwei Punkte bei (3, 4) als gleich, obwohl sich ihre Identitäten unterscheiden. in, count, index und remove können bei Listen solche gleichen Werte finden. Das übliche Ergebnis von != folgt aus __eq__.

NotImplemented ist ein Rückgabewert, der Python den anderen Operanden oder eine Ersatzlösung versuchen lässt. Es ist keine Ausnahme, die ausgelöst wird. Unterstützt keiner der Operanden Wertgleichheit, greift == auf die Identität zurück; ein Punkt und die Zeichenkette "3,4" gelten als ungleich.

Wird __eq__ ohne __hash__ definiert, sind die Instanzen nicht hashbar. Sie können dann weder Elemente einer Menge noch Schlüssel eines Wörterbuchs sein. Gleiche Objekte müssen gleiche Hashwerte haben und der Hashwert eines Schlüssels muss stabil bleiben. Wenn sich die verglichenen Attribute nie ändern, kann eine passende Hashmethode hash((self.x, self.y)) zurückgeben. Lass veränderliche Wertobjekte nicht hashbar, wenn sich ihre Gleichheitsfelder ändern können.

Eine Ordnung definieren

__lt__ stellt < bereit. Eine Klasse für Studierende kann Punktzahlen mit return self.score < other.score vergleichen. Die Punktzahlen 88, 72 und 95 werden dann zu 72, 88, 95 sortiert. min wählt die niedrigste; max wählt die höchste, indem es > und dessen reflektierten <-Vergleich verwendet.

Ist nur __lt__ definiert, kann a > b den Vergleich b < a verwenden. Python leitet <= oder >= nicht aus dieser Definition ab; sie benötigen eigene Methoden. Ist eine Ordnung nur für eine Aufgabe nützlich, übergib stattdessen eine Schlüsselfunktion:

def by_score(student):
    return student.score

ordered = sorted(students, key=by_score)
Neue Ergebnisse aus Rechnungen zurückgeben

Innerhalb einer Vektorklasse mit den Attributen x und y:

    def __add__(self, other):
        if not isinstance(other, Vector):
            return NotImplemented
        return Vector(self.x + other.x, self.y + other.y)

    def __mul__(self, factor):
        if not isinstance(factor, (int, float)):
            return NotImplemented
        return Vector(self.x * factor, self.y * factor)

    def __rmul__(self, factor):
        return self * factor

Vector(1, 2) + Vector(3, 4) erzeugt einen neuen Vektor (4, 6). Die Multiplikation des ersten Vektors mit 3 erzeugt (3, 6) und lässt ihn unverändert. __mul__ behandelt den Vektor auf der linken Seite; __rmul__ unterstützt eine Zahl auf der linken Seite. Python nimmt nicht an, dass beide Reihenfolgen dasselbe bedeuten.

Eine sinnvolle Länge bereitstellen

Definiere für eine Wiedergabeliste, die self.songs speichert, __len__ so, dass es len(self.songs) zurückgibt. Das Ergebnis muss eine nicht negative ganze Zahl sein. len(playlist) zählt dann die Lieder. In dieser Klasse führt die Länge null auch dazu, dass if playlist: als falsch ausgewertet wird; ein eigenes __bool__ hätte bei der Wahrheitswertauswertung Vorrang vor der Länge.

Wichtige Erkenntnisse

  • __eq__ definiert Wertgleichheit; gib für nicht unterstützte Operandentypen NotImplemented zurück.
  • Gleiche hashbare Objekte benötigen gleiche, stabile Hashwerte.
  • __lt__ unterstützt das Sortieren, stellt aber weder <= noch >= bereit.
  • Verwende eine Schlüsselfunktion für eine aufgabenspezifische Sortierreihenfolge.
  • Arithmetische Methoden können neue Objekte erstellen, ohne die Operanden zu verändern.
  • __rmul__ unterstützt die Multiplikation mit dem Objekt auf der rechten Seite.
  • __len__ gibt eine nicht negative ganze Zahl zurück und kann die Wahrheitswertauswertung ermöglichen, wenn kein __bool__ existiert.
5

Programme aus zusammenarbeitenden Objekten erstellen

Größere Programme verbinden Objekte mit unterschiedlichen Aufgaben. Ein Einkaufswagen kann Artikel nach Zwischensummen fragen; ein Konto kann ein anderes bitten, eine Einzahlung entgegenzunehmen. Verfolge die Referenzen und die Reihenfolge der Aufrufe, damit du erkennst, welcher Zustand sich ändert und wo ein Fehler die Ausführung stoppt. Nutze diese Ideen dann, um einen übersichtlichen Entwurf zu wählen, eine kleine Klasse zu planen und ihr öffentliches Verhalten in überschaubaren Schritten zu testen.

5.1 Objekte erstellen, die andere Objekte enthalten

Die Attribute eines Objekts können auf andere Objekte verweisen. Ein Einkaufswagen enthält Artikel, eine Bibliothek enthält Bücher und ein Kurs hat Teilnehmende. Komposition baut über diese Hat-ein-Beziehung ein größeres Objekt aus kleineren auf.

Jedem Objekt seine eigene Verantwortung geben
class Item:
    def __init__(self, name, price, quantity):
        self.name = name
        self.price = price
        self.quantity = quantity

    def subtotal(self):
        return self.price * self.quantity

class ShoppingCart:
    def __init__(self):
        self.items = []

    def add(self, item):
        if not isinstance(item, Item):
            raise TypeError("a cart holds Item objects")
        self.items.append(item)

    def total(self):
        total = 0
        for item in self.items:
            total += item.subtotal()
        return total

Der Einkaufswagen besitzt eine separate Liste, die bei der Initialisierung erstellt wird. Seine Methode add prüft das übergebene Objekt, bevor sie es anhängt. cart.add("pen") löst TypeError aus, statt Text zu speichern, der bei der Abfrage einer Zwischensumme zu einem Fehler führt.

Erstelle die Artikel vor oder während der Aufrufe:

cart = ShoppingCart()
cart.add(Item("notebook", 2.50, 4))
cart.add(Item("pen", 1.25, 3))
print(cart.total())         # 13.75
print(cart.items[0].name)   # notebook

Die Zwischensummen sind 10.0 und 3.75; der Einkaufswagen addiert sie zu 13.75. Die Kette cart.items[0].name greift zuerst auf die Liste des Einkaufswagens zu, dann auf deren erstes Objekt und schließlich auf den Namen dieses Objekts.

Arbeit an das zuständige Objekt delegieren

Der Einkaufswagen fragt jeden Artikel nach subtotal(). Das ist Delegation: Ein Objekt ruft für einen Teil einer Aufgabe die Methode eines anderen Objekts auf. Ändert ein Mengenrabatt die Berechnung einer Zwischensumme, gehört diese Regel in Item.subtotal. Der Einkaufswagen kann die zurückgegebenen Zwischensummen weiterhin addieren, ohne Preisregeln zu wiederholen.

Wer Item statt Item(...) übergibt, übergibt die Klasse und keinen gekauften Artikel. Die Typprüfung weist dieses Klassenobjekt zurück. Füge Artikel nur auf dem geprüften Weg hinzu; ein direkter Zugriff über cart.items.append(...) würde add umgehen.

Ein Objekt suchen

Füge diese Methode innerhalb von ShoppingCart hinzu:

    def find(self, name):
        for item in self.items:
            if item.name == name:
                return item
        return None

Beim ersten Treffer wird der vorhandene Artikel zurückgegeben. Gibt es keinen Treffer, wird None zurückgegeben. Prüfe found is None, bevor du found.name verwendest; None hat kein solches Attribut. Eine Methode __len__, die len(self.items) zurückgibt, könnte außerdem dafür sorgen, dass len(cart) die gespeicherten Artikelobjekte zählt, während __str__ Artikelzeilen zu einem Beleg zusammenfügen könnte.

Referenzen innerhalb von Sammlungen verfolgen

Eine Liste speichert Referenzen. Deshalb wird derselbe Artikel nicht kopiert, wenn er in zwei Einkaufswagen gelegt wird. Eine Änderung des Preises dieses Artikels wirkt sich auf die nächste Gesamtsumme beider Einkaufswagen aus. Separate Einkaufswagenlisten verhindern, dass versehentlich eine Liste gemeinsam genutzt wird, machen aber die enthaltenen Objekte nicht unabhängig. Erstelle separate Artikel, wenn die Einkaufswagen unabhängige Daten enthalten müssen.

Wichtige Erkenntnisse

  • Komposition speichert Objekte innerhalb eines anderen Objekts.
  • Bei der Delegation wird ein enthaltenes Objekt gebeten, seinen Teil einer Aufgabe auszuführen.
  • Prüfe ein Objekt vor dem Speichern, wenn spätere Methoden seinen Datentyp benötigen.
  • Eine Suche kann das passende Objekt oder None zurückgeben.
  • Separate Container können dennoch auf dasselbe enthaltene Objekt verweisen.

5.2 Objekte über Methoden miteinander interagieren lassen

Objekte können genau wie Zahlen oder Zeichenketten Methodenargumente und Rückgabewerte sein. Verfolge Empfängerobjekt, Argumente und Ergebnis getrennt: Eine Methode kann ein vorhandenes Objekt verändern, ein neues Objekt zurückgeben oder einfach einen Wert mitteilen.

Ein anderes Objekt als Eingabe verwenden

Innerhalb einer Punktklasse mit x und y kann eine Methode beide Punkte lesen:

    def midpoint(self, other):
        return Point((self.x + other.x) / 2,
                     (self.y + other.y) / 2)

Für p = Point(3, 4) und q = Point(1, 0) erstellt middle = p.midpoint(q) einen dritten Punkt bei (2.0, 2.0). Während des Aufrufs verweist self auf p und other auf q. Die Methode berechnet Koordinaten und erstellt einen neuen Punkt; sie weist keinem der ursprünglichen Punkte etwas zu.

Mit import math kann eine Abstandsmethode math.hypot(self.x - other.x, self.y - other.y) zurückgeben. Point(0, 0).distance_to(Point(3, 4)) ergibt dann 5.0. Dieser Aufruf gibt eine Zahl zurück, während midpoint ein Objekt zurückgibt.

Jedes Empfängerobjekt seine Änderungen verwalten lassen

Innerhalb einer Kontoklasse mit geprüften Methoden withdraw und deposit:

    def transfer_to(self, other, amount):
        self.withdraw(amount)
        other.deposit(amount)

Hat Maya 100 und Leo 20, hebt maya.transfer_to(leo, 30) zuerst von Mayas Konto ab, sodass 70 bleiben. Dann wird auf Leos Konto eingezahlt, sodass dort 50 stehen. Beim ersten Aufruf ist self Mayas Konto. Beim Einzahlungsaufruf ist dessen eigenes self Leos Konto.

Eine spätere Überweisung von 500 scheitert in withdraw, weil Maya nur 70 hat. Die Ausführung stoppt vor deposit, sodass beide Kontostände ihre bisherigen Werte behalten. Die Reihenfolge der Aufrufe ist wichtig. Python macht eine frühere Zustandsänderung nicht rückgängig, wenn ein späterer Aufruf eine Ausnahme auslöst; diese kurze Methode setzt voraus, dass das Empfängerkonto den Betrag annehmen kann.

Der Aufruf other.deposit(amount) führt die Regeln des Empfängerkontos an einer Stelle aus. Eine direkte Änderung von other.balance würde sie umgehen.

Objekte verfolgen, nicht nur Variablennamen

Zeichne jede Instanz als Kasten mit ihren Attributen. Zeichne von jeder Variablen einen Pfeil zu ihrem Kasten. Bestimme bei einem Aufruf, welcher Kasten als self übergeben wird und welche Kästen als Argumente übergeben werden. Aktualisiere den betroffenen Kasten nach jeder erfolgreichen Zeile, die den Zustand ändert. Zwei Pfeile zu einem Kasten bedeuten, dass eine Änderung über einen der Namen dasselbe Objekt erreicht.

Auch eine einfache Funktion kann über mehrere Objekte hinweg arbeiten. total_balance(accounts) kann Konten durchlaufen und ihre Kontostände addieren. Diese Berechnung über die gesamte Liste muss nicht zu einem einzelnen Konto gehören.

Eine fehlende Beziehung darstellen

Ein Buch kann mit self.borrower = None beginnen und später ein Mitgliedsobjekt speichern. Prüfe die Beziehung, bevor du ein Attribut des Mitglieds liest:

if book.borrower is not None:
    print(book.borrower.name)

Andernfalls scheitert book.borrower.name, wenn das Buch keinen Entleiher hat. Klassen können oberhalb einer Funktion main() definiert werden, die die Objekte erstellt und verbindet. Wird main() unter if __name__ == "__main__": aufgerufen, werden diese Aktionen beim Importieren der Klassen nicht ausgeführt.

Wichtige Erkenntnisse

  • Erkenne das Empfängerobjekt als self und das Objektargument als eigenen Parameter.
  • Eine Methode kann ein neues Objekt zurückgeben und dabei ihre Eingaben unverändert lassen.
  • Aufrufe erfolgen der Reihe nach; eine Ausnahme stoppt spätere Aufrufe, macht frühere Änderungen aber nicht rückgängig.
  • Verwende die öffentlichen Methoden eines anderen Objekts, um dessen Regeln anzuwenden.
  • Prüfe auf None, bevor du einer optionalen Objektbeziehung folgst.
  • Eine Funktion kann Berechnungen über mehrere Objekte hinweg organisieren.

5.3 Entscheiden, wann eine Klasse ein Programm übersichtlicher macht

Eine Klasse ist sinnvoll, wenn zusammengehörende Daten und wiederholte Operationen gemeinsam leichter zu verstehen sind. Du musst nicht jede Funktion und jeden Datensatz in eine Klasse umwandeln. Wähle die Struktur, die die Verantwortlichkeiten des Programms deutlich macht.

Zusammengehörende Daten und Verhalten erkennen

Klassen helfen, wenn mehrere Funktionen immer wieder dieselbe Gruppe von Werten entgegennehmen, viele Datensätze dieselbe Struktur haben und Zustandsänderungen gemeinsamen Regeln folgen müssen. Mehrere Konten, die alle Ein- und Auszahlungen unterstützen, passen gut dazu. Eine einzelne Berechnung kann eine Funktion bleiben. Ein fester, schreibgeschützter Datensatz kann ein Tupel oder Wörterbuch bleiben.

Eine Klasse, die nur eine Einrichtung und eine einmalige Operation enthält, schafft oft mehr Aufwand als nützliche Struktur. Frag dich, was eine Instanz darstellt und welche wiederholten Aktionen zu ihr gehören. Kannst du diese Fragen nicht einfach beantworten, überdenke den Entwurf.

Eine Operation zu ihren Daten verschieben

Ein Konto auf Wörterbuchbasis könnte so beginnen:

account = {"owner": "Maya", "balance": 50}

def deposit(account, amount):
    account["balance"] += amount

Die Klassenversion kann dieselbe Operation neben ihrem Zustand und ihren Regeln platzieren:

class BankAccount:
    def __init__(self, owner, balance=0):
        self.owner = owner
        self.balance = balance

    def deposit(self, amount):
        if amount <= 0:
            raise ValueError("deposit must be positive")
        self.balance += amount

    def __repr__(self):
        return f"BankAccount({self.owner!r}, {self.balance})"

Nach acct = BankAccount("Maya", 50) und acct.deposit(25) ist seine Darstellung BankAccount('Maya', 75). Die Regel für positive Einzahlungen wird nun jedes Mal ausgeführt, wenn der aufrufende Code diese Methode verwendet. Das Lesen von account["balence"] würde KeyError auslösen; das Lesen von acct.balence löst AttributeError aus. Eine Klasse beseitigt keine Schreibfehler, gibt den Daten und ihren Operationen aber einen benannten Platz.

Anhand einer kurzen Beschreibung planen

Bei „Eine Bibliothek verleiht Bücher an Mitglieder. Ein Mitglied kann höchstens 3 Bücher ausleihen“ deuten die Substantive auf Book, Member und Library hin. Die Verben deuten auf Methoden zum Ausleihen und Zurückgeben hin.

  1. Liste auf, was jede Instanz weiß: Titel, Autor und Entleiher eines Buches; Name und ausgeliehene Bücher eines Mitglieds; Bücher und Mitglieder einer Bibliothek.
  2. Bestimme die Regeln: Ein Buch darf nicht bereits ausgeliehen sein und ein Mitglied darf MAX_LOANS = 3 nicht überschreiten.
  3. Setze jede Regel in die Operation, die die Beziehung verändert, etwa Library.check_out(book, member).
  4. Schreibe die Initialisierung und eine nützliche Darstellung, ergänze und teste dann eine Aktion nach der anderen.

Unterschiedliche Titel benötigen unterschiedliche Instanzen von Book, keine eigenen Klassen für jeden Titel. Verwende für einzelne Objekte Substantive im Singular wie Book; benenne eine Sammlung nach der Sammlung, etwa Library. Halte die Aufgabe jeder Klasse so klar, dass du sie in einem Satz beschreiben kannst.

Beobachtbares Verhalten testen
acct = BankAccount("Maya", 50)
acct.deposit(25)
assert acct.balance == 75

assert löst AssertionError aus, wenn seine Bedingung falsch ist. Teste auch abgelehnte Aktionen: Fange die erwartete Ausnahme ab und prüfe, ob der Zustand unverändert geblieben ist. Verwende für Eingaben des aufrufenden Codes eine ausdrückliche Validierung mit raise; Zusicherungen sind Prüfungen während der Entwicklung und können deaktiviert werden, wenn Python mit Optimierung läuft.

Wichtige Erkenntnisse

  • Wähle eine Klasse, wenn zusammengehörender Zustand und wiederholte Operationen von einem gemeinsamen Platz profitieren.
  • Belasse eine einfache Berechnung als Funktion, wenn kein dauerhafter Objektzustand benötigt wird.
  • Plane Attribute anhand der Daten und Methoden anhand der Aktionen und Regeln.
  • Modelliere unterschiedliche Datenwerte als Instanzen einer Klasse.
  • Teste sowohl erfolgreiche Aktualisierungen als auch abgelehnte Änderungen.

Klassen in Python: Beispiele

5 Interaktive Lektionen

1

Von vertrauten Werten zu deiner ersten Klasse

11 Schritte
Verfolge Methodenaufrufe und gemeinsam genutzte Referenzen und erstelle dann zwei Objekte mit eigenen Attributen.
  1. 1
    EinführungMit bekannten Objekten beginnen

    Eine Liste, eine Zeichenkette und eine Zahl sind allesamt Objekte. Ihre Datentypen bestimmen, welche Operationen sie unterstützen, und jeder Wert hat seine eigene Identität.

    Beginne damit, eine Zeichenkettenmethode und eine Listenmethode nachzuvollziehen. Nutze dann dieselben Ideen, um eine einfache Klasse zu erstellen, deren Instanzen unterschiedliche Daten speichern. Stelle dir immer wieder zwei Fragen: Auf welches Objekt verweist dieser Name und was gibt dieser Aufruf zurück?

  2. 2
    BeispielDen Datentyp eines Werts abfragen

    Python kann dir sagen, welche Art von Objekt ein Wert ist.

    text = "river"
    values = [4, 2]
    print(type(text))              # <class 'str'>
    print(isinstance(values, list))  # True
    

    Die Zeichenkette und die Liste bieten unterschiedliche Methoden an, weil sie unterschiedliche Datentypen haben. Mit dir(values) kannst du die auf der Liste verfügbaren Namen untersuchen, darunter gewöhnliche Methoden und Spezialmethoden.

  3. 3
    BeispielEine zurückgegebene Zeichenkette verfolgen

    Eine Zeichenkettenmethode kann einen neuen Wert erzeugen, ohne den ursprünglichen zu ersetzen.

    name = "robin"
    result = name.title()
    print(result)  # Robin
    print(name)    # robin
    

    title() gibt eine neue Zeichenkette zurück. Die Zuweisung speichert dieses Ergebnis unter result, während name weiterhin auf "robin" verweist. Mit name = name.title() würde name stattdessen auf die zurückgegebene Zeichenkette verweisen.

  4. 4
    BeispielEine direkte Listenänderung verfolgen

    Vergleiche den Zeichenkettenaufruf mit dem Sortieren einer Liste.

    values = [4, 2]
    result = values.sort()
    print(values)  # [2, 4]
    print(result)  # None
    

    Die Liste selbst ändert sich und der Rückgabewert ist None. Würdest du das Ergebnis des Aufrufs wieder values zuweisen, würde die Listenreferenz dieses Namens durch None ersetzt. Verwende values.sort() allein, wenn du die vorhandene Liste verändern möchtest.

  5. 5
    HerausforderungWo erscheint das angehängte Element?

    Sage beide ausgegebenen Listen voraus.

    a = [7]
    b = a
    c = [7]
    b.append(2)
    print(a, c)
    

    ---reveal---

    Die Ausgabe ist [7, 2] [7]. a und b verweisen auf eine Liste, sodass das Anhängen über b die Liste verändert, die über a erreichbar ist. c enthält eine separate Liste. Die Listen waren anfangs gleich, aber a is c war falsch.

  6. 6
    TippReferenzen vor dem Nachvollziehen von Änderungen zeichnen

    Zeichne für jede separat erstellte Liste einen Kasten. Lass sowohl a als auch b auf den ersten Kasten und c auf den zweiten zeigen. Ein Anhängen verändert den Kasten; eine Zuweisung verändert, wohin ein Name zeigt.

    Unterscheide auch eine Methode von ihrem Aufruf: name.title liefert ein Methodenobjekt, während name.title() es ausführt. Klammern können den Unterschied ausmachen, ob du ein Verhalten erhältst oder sein Ergebnis.

  7. 7
    AnalogieEin Formular, mehrere ausgefüllte Kopien

    Stell dir eine Klasse als leeres Formular vor, das beschreibt, welche Informationen eine Art von Objekt enthält. Eine Instanz ist eine ausgefüllte Kopie mit eigenen Daten.

    Eine Klasse Badge kann jeden Besucherausweis in einem Programm darstellen. Eine Instanz enthält den Namen eines Besuchers, eine andere einen anderen Namen. Die Klasse beschreibt die gemeinsame Art von Objekt. Du brauchst keine neue Klasse für jeden Wert, der auf dem Formular steht.

  8. 8
    BeispielDen Datentyp definieren und zwei Instanzen erstellen

    Verwende eine minimale Klasse, während du lernst, wie Instanzen funktionieren.

    class Badge:
        pass
    
    first = Badge()
    second = Badge()
    first.name = "Rae"
    second.name = "Ivo"
    

    pass stellt einen leeren Körper bereit. Jeder Klassenaufruf erstellt eine Instanz und die Zuweisungen mit Punktnotation speichern Daten auf dem ausgewählten Objekt. first is second ist falsch. first = Badge würde der Klasse stattdessen einen weiteren Namen geben, ohne eine Instanz zu erstellen.

  9. 9
    HerausforderungEin falsch geschriebenes Attribut finden

    Arbeite mit den beiden Besucherausweisen weiter:

    first.nmae = "Tess"
    print(first.name, second.name)
    

    Was erscheint?

    ---reveal---

    Die Ausgabe ist Rae Ivo. Die Zuweisung erstellt ein separates Attribut namens nmae; sie verändert name nicht. Das Lesen eines nicht vorhandenen Attributs löst AttributeError aus, aber die Zuweisung an einen neuen Namen ist erlaubt. Prüfe bei einem überraschenden Leseergebnis die Schreibweise sowohl beim Schreiben als auch beim Lesen.

  10. 10
    HerausforderungInstanzen und Aliase kombinieren

    Arbeite mit first und second aus dem Besucherausweisbeispiel weiter:

    copy_name = first
    copy_name.name = "Noor"
    print(first.name, second.name)
    

    ---reveal---

    Die Ausgabe ist Noor Ivo. copy_name ist ein Alias für den ersten Besucherausweis, daher verändert die Zuweisung dieses Objekt. Der zweite Besucherausweis bleibt ein separates Objekt. Durch das Erstellen von Instanzen bestimmst du, wie viele Objekte existieren; durch Zuweisungen bestimmst du, auf welche Objekte die Namen verweisen.

  11. 11
    ZusammenfassungEin weiteres Programm auf Papier nachvollziehen

    Probiere ein kurzes Programm mit zwei Klassenaufrufen und einem dritten Namen aus, dem die erste Instanz zugewiesen wird. Gib den Objekten unterschiedliche Attribute und ändere dann eines über den Alias.

    Zeichne vor der Ausführung die Objektkästen und sage jeden Lesezugriff voraus. Unterscheidet sich eine Vorhersage von der Ausgabe, prüfe die Schreibweise der Attribute und die Pfeile von den Namen zu den Objekten. So unterscheidest du einen Einrichtungsfehler von einem Referenzfehler.

2

Objekte mit verlässlichen Anfangsdaten erstellen

14 Schritte
Initialisiere eine kleine Aufgabensammlung, unterscheide gemeinsame Einstellungen von individuellen Daten und weise eine ungültige Einrichtung zurück.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungEine Aufgabensammlung einrichten
  2. 2
    ErklärungPython einen Initialisierer geben
  3. 3
    BeispielEinen Aufruf seinen Parametern zuordnen
  4. 4
    HerausforderungDas fehlende Attribut erkennen
  5. 5
    BeispielEine optionale Anfangsliste entgegennehmen
  6. 6
    TippPrüfen, wie weit die Kopie reicht
  7. 7
    ErklärungDaten über die Klasse hinzufügen
  8. 8
    BeispielEine verdeckende Zuweisung verfolgen
  9. 9
    HerausforderungDen gemeinsamen Zähler korrigieren
  10. 10
    ErklärungEine unbrauchbare Obergrenze zurückweisen
  11. 11
    BeispielFehler und Fehlerbehandlung wählen
  12. 12
    HerausforderungWeist eine Ausgabe die Einrichtung zurück?
  13. 13
    HerausforderungBei einem Fehler das vorherige Objekt behalten
  14. 14
    ZusammenfassungDie Einrichtung aus Sicht des aufrufenden Codes prüfen
3

Zustand über Methoden und Properties steuern

16 Schritte
Erstelle einen geprüften Bestandszähler, verfolge einen Alias und stelle einen validierten Attributzugriff bereit.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungEinen Bestandszähler nutzbar machen
  2. 2
    BeispielMit einer gespeicherten Menge beginnen
  3. 3
    ErklärungDas Empfängerobjekt als self übergeben lassen
  4. 4
    HerausforderungEin Ergebnis wiederverwendbar machen
  5. 5
    BeispielNach Prüfung der Menge Bestand hinzufügen
  6. 6
    BeispielEine Entnahme vor der Subtraktion zurückweisen
  7. 7
    HerausforderungEine Änderung über einen Alias verfolgen
  8. 8
    VerbindungDie richtige Zustandsebene kopieren
  9. 9
    ErklärungInterne Speicherung kennzeichnen
  10. 10
    BeispielÜber eine Property lesen
  11. 11
    BeispielGeprüfte öffentliche Zuweisungen erlauben
  12. 12
    HerausforderungEinen rekursiven Setter vermeiden
  13. 13
    KernaussageEinen Wert beim Lesen berechnen
  14. 14
    HerausforderungEinen Setter mit einem Alias kombinieren
  15. 15
    TippDefinition und Aufruf zusammen lesen
  16. 16
    ZusammenfassungEine Operation nach der anderen testen
4

Objekte für Python-Ausdrücke passend machen

17 Schritte
Gib einem Koordinatenpaar nützliche Darstellungen, Vergleiche, arithmetische Operationen und ein klares Verhalten bei eingebauten Funktionen.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungDie Bedeutung eines Objekts festlegen
  2. 2
    BeispielMit einem Punkt beginnen
  3. 3
    BeispielText für die Untersuchung ergänzen
  4. 4
    HerausforderungDie Darstellung einer Liste vorhersagen
  5. 5
    TippIn beiden Darstellungsmethoden Text zurückgeben
  6. 6
    BeispielKoordinatenwerte vergleichen
  7. 7
    KernaussageNicht unterstützte Vergleiche Python überlassen
  8. 8
    HerausforderungKönnen gleiche Paare in eine Menge?
  9. 9
    BeispielEine Koordinatenordnung wählen
  10. 10
    VerbindungEine Ordnung kann zu einer Aufgabe gehören
  11. 11
    BeispielAddieren, ohne die Operanden zu verändern
  12. 12
    BeispielBeide Multiplikationsreihenfolgen unterstützen
  13. 13
    HerausforderungEin neues Ergebnis von einem Alias unterscheiden
  14. 14
    ErklärungDie Länge für eine Sammlung verwenden
  15. 15
    HerausforderungDen Zweig bei leerer Warteschlange vorhersagen
  16. 16
    TippDie Bedeutung erkennbar halten
  17. 17
    ZusammenfassungJeden Ausdruck einzeln prüfen
5

Objekte mit klaren Aufgaben verbinden

15 Schritte
Erstelle eine kleine Bestellung aus Positionsobjekten, verfolge gemeinsam genutzte Referenzen und teste eine abgelehnte Operation.

Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.

  1. 1
    EinführungEine Bestellung aus kleineren Teilen erstellen
  2. 2
    BeispielEiner Position eine eigene Berechnung geben
  3. 3
    BeispielPositionen in einer Bestellung speichern
  4. 4
    BeispielJede Kostenberechnung delegieren
  5. 5
    HerausforderungEine von zwei Bestellungen gemeinsam genutzte Position verfolgen
  6. 6
    TippEin fehlendes Suchergebnis abfangen
  7. 7
    ErklärungEin Objekt an eine andere Methode übergeben
  8. 8
    BeispielEmpfängerobjekt und Ergebnis verfolgen
  9. 9
    HerausforderungWo stoppt eine fehlgeschlagene Kombination?
  10. 10
    VerbindungAufrufe verfolgen, die zwei Objekte verändern
  11. 11
    ErklärungEntscheiden, welches Verhalten zusammengehört
  12. 12
    HerausforderungEine Klasse für jedes Produkt vermeiden
  13. 13
    BeispielDie geprüfte öffentliche Methode zum Hinzufügen testen
  14. 14
    HerausforderungEinen Test für den kombinierten Entwurf wählen
  15. 15
    ZusammenfassungEine eigene kleine Zusammenarbeit planen

Klassen in Python: Übungsaufgaben

50 Übungsfragen in 5 Sets

Set 1: Objekte, Referenzen und verlässliche Einrichtung10 Übungsfragen

Frage 1 von 10

Was gibt dieser Code aus?

label = "cedar"
label.upper()
print(label)
  1. Großgeschriebener Text: CEDAR
  2. Der Wert None
  3. Ursprünglicher Text: cedar
  4. Text mit großem Anfangsbuchstaben: Cedar
Antwort zeigenAntwort ausblenden
Antwort: C
upper() gibt eine neue Zeichenkette zurück, aber dieser Aufruf speichert das Ergebnis nicht. Der Name label verweist weiterhin auf die ursprüngliche Zeichenkette, daher ist die Ausgabe cedar. Wer CEDAR erwartet, behandelt die Zeichenkettenmethode als direkte Änderung; Zeichenketten sind unveränderlich.

Frage 2 von 10

Was gibt dieser Code aus?

a = [6, 2]
b = a
a = sorted(a)
b.append(9)
print(a, b)
  1. [2, 6] [6, 2, 9]
  2. [2, 6, 9] [2, 6, 9]
  3. [6, 2, 9] [2, 6]
  4. [2, 6] [2, 6, 9]
Antwort zeigenAntwort ausblenden
Antwort: A
sorted(a) erstellt eine neue sortierte Liste und die Zuweisung lässt a auf sie verweisen. b verweist weiterhin auf die ursprüngliche Liste, sodass das Anhängen diese Liste zu [6, 2, 9] verändert. Wer beide Namen weiterhin derselben Liste zuordnet, übersieht die erneute Zuweisung an a.

Frage 3 von 10

Was enthält first.name am Ende?

class Badge:
    pass
first = Badge()
second = Badge()
first.name = "Rae"
second.name = "Ivo"
first.nmae = "Sol"
  1. "Sol"
  2. "Ivo"
  3. Keinen Wert; die Zuweisung scheitert.
  4. "Rae"
Antwort zeigenAntwort ausblenden
Antwort: D
first.name wurde "Rae" zugewiesen und erhält keinen neuen Wert. Das falsch geschriebene nmae erstellt ein separates Attribut auf first, während second.name zu einem anderen Objekt gehört. Eine Zuweisung an ein neues Attribut ist erlaubt, daher löst der Tippfehler selbst keinen Fehler aus.

Frage 4 von 10

Ein Programm benötigt drei Sensoren mit unterschiedlichen Bezeichnungen, aber denselben Methoden zum Ablesen und Zurücksetzen. Wie sollten seine Klassen und Objekte angeordnet sein?
  1. Eine Sensorklasse pro Bezeichnung mit jeweils einem Objekt.
  2. Eine Sensorklasse mit drei separaten Instanzen.
  3. Eine Sensorinstanz mit drei Namen dafür.
  4. Drei Bezeichnungsklassen mit einer gemeinsamen Sensorinstanz.
Antwort zeigenAntwort ausblenden
Antwort: B
Die Sensoren haben dieselbe Art von Verhalten, sodass eine Klasse ihre Methoden zum Ablesen und Zurücksetzen definieren kann. Separate Instanzen können ihre unterschiedlichen Bezeichnungen und aktuellen Messwerte enthalten. Drei Namen für eine einzige Instanz würden alle auf denselben Zustand zugreifen. Das Zurücksetzen des Sensors über einen der Namen würde daher den gemeinsam genutzten Sensor zurücksetzen.

Frage 5 von 10

Was gibt dieser Code aus?

class Counter:
    def __init__(self, start=4):
        self.value = start
c = Counter(9)
print(c.value)
  1. 4
  2. 0
  3. 9
  4. None
Antwort zeigenAntwort ausblenden
Antwort: C
Python übergibt das neue Objekt als self und 9 als start. Der Initialisierer speichert diesen Wert in self.value, daher ist die Ausgabe 9. Der Standardwert 4 wird nur verwendet, wenn der aufrufende Code start weglässt; er ersetzt kein ausdrücklich übergebenes Argument.

Frage 6 von 10

Warum scheitert die letzte Zeile?

class Lamp:
    def __init__(self, brightness):
        brightness = brightness
lamp = Lamp(7)
print(lamp.brightness)
  1. Die Zuweisung ändert nur einen lokalen Parameter.
  2. Der Klassenaufruf lässt den Parameter ungesetzt.
  3. Das Attribut wird stattdessen auf der Klasse gespeichert.
  4. Der Initialisierer muss die Helligkeit zurückgeben.
Antwort zeigenAntwort ausblenden
Antwort: A
brightness = brightness weist dem lokalen Parameter erneut einen Wert zu und erstellt kein Attribut auf der Lampe. Der Lesezugriff löst daher AttributeError aus; die Einrichtung sollte self.brightness = brightness speichern. Die Rückgabe der Zahl aus __init__ würde einen separaten TypeError verursachen und das Attribut nicht erstellen.

Frage 7 von 10

Was gibt dieser Code aus?

class Folder:
    def __init__(self, tags=[]):
        self.tags = tags
a = Folder()
b = Folder()
a.tags.append("urgent")
a.tags = []
print(b.tags, a.tags)
  1. [] []
  2. ['urgent'] ['urgent']
  3. [] ['urgent']
  4. ['urgent'] []
Antwort zeigenAntwort ausblenden
Antwort: D
Durch die weggelassenen Argumente speichern beide Objekte zunächst dieselbe Standardliste. Das Anhängen fügt "urgent" in diese gemeinsam genutzte Liste ein; die spätere Zuweisung gibt nur a eine neue leere Liste. Wer zwei leere Listen erwartet, verwechselt das Ersetzen einer Attributreferenz mit dem Leeren des ursprünglichen gemeinsam genutzten Objekts.

Frage 8 von 10

Was gibt dieser Code aus?

class Ticket:
    fee = 3
x = Ticket()
y = Ticket()
x.fee = 8
Ticket.fee = 5
print(x.fee, y.fee)
  1. 5 5
  2. 8 5
  3. 8 3
  4. 3 5
Antwort zeigenAntwort ausblenden
Antwort: B
Die Zuweisung an x.fee erstellt ein Instanzattribut, das den Klassenwert verdeckt. y hat keine eigene Gebühr und findet daher nach der Klassenaktualisierung den Wert 5 auf Ticket. Wer 5 5 erwartet, übersieht den separaten Wert auf x, den die Zuweisung an die Klasse nicht ersetzt.

Frage 9 von 10

Was gibt dieser Code aus?

class Job:
    count = 0
    def __init__(self):
        self.count += 1
a = Job()
Job.count = 10
b = Job()
print(a.count, b.count, Job.count)
  1. 1 11 10
  2. 11 11 10
  3. 1 1 10
  4. 1 11 11
Antwort zeigenAntwort ausblenden
Antwort: A
Bei der Erstellung von a wird der Klassenzähler 0 gelesen und der Instanzzähler 1 gespeichert. Nachdem sich der Klassenwert auf 10 geändert hat, wird bei der Erstellung von b dessen eigener Wert 11 gespeichert; keiner der Initialisierer aktualisiert Job.count. Das Ergebnis 1 11 11 behandelt die erweiterte Instanzzuweisung als Aktualisierung eines Klassenzählers.

Frage 10 von 10

Was gibt dieser Code aus?

class Batch:
    def __init__(self, size):
        if size <= 0:
            raise ValueError("size must be positive")
        self.size = size
batch = Batch(6)
try:
    batch = Batch(0)
except ValueError:
    pass
print(batch.size)
  1. 0
  2. None
  3. 6
  4. ValueError
Antwort zeigenAntwort ausblenden
Antwort: C
Der Aufruf Batch(0) löst eine Ausnahme aus, bevor er einen Wert zurückgibt, sodass die Zuweisung an batch nicht stattfindet. Die Ausnahme wird abgefangen und batch verweist weiterhin auf das vorherige gültige Objekt mit der Größe 6. Ein fehlgeschlagener Erstellungsaufruf ersetzt die vorhandene Referenz des aufrufenden Codes nicht durch ein Teilergebnis.
Set 2: Methoden, Zustandsänderungen und Properties10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Welches Argument übergibt Python als self, wenn das Programm panel.area() aufruft?
  1. Das Klassenobjekt Panel.
  2. Das Objekt, auf das panel verweist.
  3. Der von area zurückgegebene Wert.
  4. Das erste Attribut von panel.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Welche Änderung ermöglicht dem aufrufenden Code, double zu berechnen?

class Pace:
    def __init__(self, minutes):
        self.minutes = minutes
    def seconds(self):
        print(self.minutes * 60)
p = Pace(3)
double = p.seconds() * 2
  1. p.seconds ohne Klammern aufrufen.
  2. p ausdrücklich an p.seconds(p) übergeben.
  3. self aus dem Initialisierer zurückgeben.
  4. Das Produkt innerhalb von seconds zurückgeben.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Ein Konstruktor verlangt eine Liste von Messwerten und weist jeden anderen Datentyp vor dem Speichern zurück. Welche Ausnahme beschreibt am besten, dass der aufrufende Code die Zeichenkette "12,14" übergibt?
  1. TypeError
  2. ValueError
  3. AttributeError
  4. AssertionError
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Was gibt dieser Code aus?

class Tank:
    def __init__(self):
        self.level = 5
    def add(self, amount):
        self.level += amount
a = Tank()
b = a
result = b.add(4)
print(a.level, result)
  1. 5 None
  2. 9 9
  3. 9 None
  4. 5 9
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Was gibt dieser Code aus?

import copy
class Log:
    def __init__(self):
        self.entries = []
a = Log()
b = copy.copy(a)
b.entries.append("open")
b.entries = ["closed"]
print(a.entries, b.entries, a is b)
  1. [] ['closed'] False
  2. ['closed'] ['closed'] True
  3. ['open'] ['open'] False
  4. ['open'] ['closed'] False
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Eine Sitzung weist Namen zurück, die nach dem Entfernen von Leerzeichen am Rand leer sind. Welcher Initialisiererkörper setzt diese Regel für name durch?
  1. if not name: raise ValueError("name required")

    self.name = name.strip()

  2. name = name.strip()

    if not name: raise ValueError("name required")

    self.name = name

  3. self.name = name.strip()

    if not name: raise ValueError("name required")

  4. if name == "": raise ValueError("name required")

    self.name = name

Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Warum ruft eine Zuweisung an reading.value diesen Setter wiederholt auf?

class Reading:
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, number):
        self.value = number
  1. Die Zuweisung verwendet erneut den Namen der Property.
  2. Der Getter liest einen anderen Attributnamen.
  3. Der Setter benötigt einen ausdrücklichen Rückgabewert.
  4. Der Dekorator sollte stattdessen die Klasse nennen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Zähler muss nicht negativ bleiben. Seine Methode remove(n) muss nicht positive Mengen und Entnahmen zurückweisen, die größer als der aktuelle Wert sind. Welche Reihenfolge lässt den Zustand bei beiden Zurückweisungen unverändert?
  1. n abziehen; sein Vorzeichen prüfen; den neuen Wert prüfen.
  2. Das Vorzeichen prüfen; n abziehen; den neuen Wert prüfen.
  3. Das Vorzeichen prüfen; den verfügbaren Wert prüfen; n abziehen.
  4. Den verfügbaren Wert prüfen; n abziehen; das Vorzeichen prüfen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Was gibt dieser Code aus?

class Dial:
    def __init__(self, value):
        self.value = value
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, number):
        if not 0 <= number <= 9:
            raise ValueError("out of range")
        self._value = number
d = Dial(4)
try:
    d.value = 12
except ValueError:
    pass
print(d.value)
  1. 12
  2. 4
  3. 9
  4. None
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Eine Klasse berechnet area mit einer schreibgeschützten Property aus width und height. Ein Objekt hat die Breite 6 und die Höhe 2; seiner Breite wird dann 8 zugewiesen. Was gibt das Lesen von obj.area zurück?
  1. 12
  2. 6
  3. 16
  4. 8
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 3: Lesbare Darstellungen und nützliche Operatoren10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Eine Klasse definiert sowohl __str__ als auch __repr__. Welche Methode liefert den Text einer Instanz, wenn sie in einer ausgegebenen Liste erscheint?
  1. __str__
  2. __init__
  3. __len__
  4. __repr__
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Was gibt dieser Code aus?

class Tag:
    def __init__(self, text):
        self.text = text
    def __repr__(self):
        return f"Tag({self.text!r})"
t = Tag("ok")
print(t)
  1. Tag('ok')
  2. ok
  3. Tag(ok)
  4. 'ok'
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Warum löst str(marker) einen TypeError aus, wenn seine Methode __str__ nur print(self.code) aufruft?
  1. Der Methodenname hat zu viele Unterstriche.
  2. Der ausgegebene Code muss einfache Anführungszeichen verwenden.
  3. Die Methode gibt None statt einer Zeichenkette zurück.
  4. Der aufrufende Code muss marker.__str__() direkt aufrufen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Eine veränderliche Klasse Label definiert Gleichheit anhand ihres Textes und definiert kein __hash__. Zwei Beschriftungen enthalten denselben Text. Was geschieht, wenn sie in eine Menge eingefügt werden?
  1. Sie bilden zwei Einträge, weil ihre Identitäten verschieden sind.
  2. Das Erstellen der Menge löst einen Fehler für einen nicht hashbaren Typ aus.
  3. Sie bilden einen Eintrag, weil ihr Text übereinstimmt.
  4. Das Erstellen der Menge wandelt ihren Text in Schlüssel um.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Eine Klasse Mark definiert nur __lt__ zum Vergleich numerischer Punktzahlen und keine weiteren eigenen Vergleiche. Was geschieht bei a mit der Punktzahl 2 und b mit der Punktzahl 7?
  1. a > b ist falsch; a <= b ist wahr.
  2. a > b löst eine Ausnahme aus; a <= b ist wahr.
  3. a > b und a <= b lösen Ausnahmen aus.
  4. a > b ist falsch; a <= b löst eine Ausnahme aus.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Ein Vector definiert __mul__ für vector * number, aber keine reflektierte Multiplikationsmethode. Welche Methode sollte ergänzt werden, um auch number * vector zu unterstützen?
  1. __rmul__
  2. __add__
  3. __lt__
  4. __len__
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine Klasse definiert __eq__ anhand von code und __hash__ als hash(self.code). Ihre Objekte werden als Wörterbuchschlüssel verwendet. Welche Entwurfsänderung macht das Verhalten der Schlüssel zuverlässig?
  1. Den Hashwert bei jedem fehlgeschlagenen Nachschlagen ändern.
  2. id(self) als Hashwert für jedes Objekt verwenden.
  3. code unverändert lassen, solange ein Objekt Schlüssel ist.
  4. Identität vergleichen und den Hashwert von code beibehalten.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Eine Klasse Queue definiert __len__ als Anzahl der ausstehenden Aufträge und definiert kein __bool__. Was sind len(q) und bool(q), wenn keine Aufträge ausstehen?
  1. 0 und True
  2. 0 und False
  3. None und False
  4. 1 und True
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Was gibt die letzte Zeile aus?

class Offset:
    def __init__(self, value):
        self.value = value
    def __add__(self, other):
        return Offset(self.value + other.value)
a = Offset(6)
b = a
a = a + Offset(4)
print(a.value, b.value, a is b)
  1. 10 6 False
  2. 10 10 True
  3. 6 10 False
  4. 10 10 False
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Rank.__lt__ ordnet Datensätze nach Priorität. Ein Bericht muss diese Datensätze stattdessen nach Erstellungszeit sortieren, ohne ihre übliche Ordnung zu ändern. Welches Vorgehen passt?
  1. __lt__ für jeden Datensatz durch einen Zeitvergleich ersetzen.
  2. Jedem Datensatz eine neue Klasse für die zeitliche Berichtsordnung geben.
  3. Die Priorität jedes Datensatzes zuerst in seine Erstellungszeit ändern.
  4. sorted mit einer Schlüsselfunktion aufrufen, die die Erstellungszeit zurückgibt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 4: Zusammenarbeitende Objekte und übersichtliche Entwürfe10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Ein Workshop speichert Tool-Objekte in self.tools. Was liest workshop.tools[0].label?
  1. Die eigene Bezeichnung der Werkstatt.
  2. Die Bezeichnungen aller gespeicherten Werkzeuge.
  3. Die Bezeichnung des ersten gespeicherten Werkzeugs.
  4. Die Anzahl der gespeicherten Bezeichnungen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Ein Warenkorb berechnet seine Gesamtsumme, indem er für jede gespeicherte Position line.cost() aufruft. Ein Mengenrabatt ändert die Berechnung der Kosten jeder Position. Wohin gehört diese Regel?
  1. In die Listeninitialisierung des Warenkorbs.
  2. In die Methode cost der Positionsklasse.
  3. In jeden Code, der einen Warenkorb ausgibt.
  4. In die Schleife des Warenkorbs nach jedem Aufruf.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Welche Gesamtsumme gibt der Code aus?

class Line:
    def __init__(self, rate, count):
        self.rate = rate
        self.count = count
    def cost(self):
        return self.rate * self.count
x = Line(4, 3)
a = [x]
b = [x, Line(2, 5)]
a[0].count = 6
print(sum(line.cost() for line in b))
  1. 22
  2. 34
  3. 24
  4. 28
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

find(name) einer Sammlung gibt bei Erfolg ein Objekt und bei Misserfolg None zurück. Welcher aufrufende Code behandelt beide Fälle, bevor er result.name liest?
  1. result.name lesen, dann result is None prüfen.
  2. Vor der Ausgabe des Namens if result.name: verwenden.
  3. Vor dem Lesen if type(result) is None: verwenden.
  4. Vor dem Lesen if result is not None: verwenden.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Eine Methode Position.midpoint(other) gibt eine neue Position zurück, deren Koordinaten die arithmetischen Mittel sind. Wenn a bei (2, 8) und b bei (10, 4) liegt, was bleibt nach c = a.midpoint(b)?
  1. c bei (6, 6); a und b unverändert.
  2. a bei (6, 6); c verweist auf a.
  3. b bei (6, 6); c verweist auf b.
  4. c bei (12, 12); a und b unverändert.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

send_to(other, n) ruft zuerst self.remove(n) und dann other.add(n) auf. remove weist eine Menge über dem Bestand des Senders zurück, bevor etwas geändert wird; add akzeptiert positive Mengen. Ausgehend von einem Senderbestand von 9 und einem Empfängerbestand von 4 gelingt eine Übertragung von 3. Danach wird eine Übertragung von 8 versucht und ihre Ausnahme abgefangen. Welche Bestände bleiben?
  1. Sender 9, Empfänger 4.
  2. Sender 6, Empfänger 15.
  3. Sender 6, Empfänger 7.
  4. Sender -2, Empfänger 15.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine Übertragung zieht Bestand vom Sender ab und ruft dann die Methode add des Empfängers auf. Der Empfänger weist die Menge zurück, bevor er seinen eigenen Bestand ändert. Es gibt keinen Code zum Rückgängigmachen und der aufrufende Code fängt die Ausnahme ab. Welcher Zustand bleibt?
  1. Sender unverändert; Empfänger unverändert.
  2. Sender verringert; Empfänger unverändert.
  3. Sender verringert; Empfänger erhöht.
  4. Sender unverändert; Empfänger erhöht.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

Ein Skript rechnet eine eingegebene Temperatur um und gibt das Ergebnis einmal aus. Es benötigt keinen gespeicherten Zustand und kein wiederholtes Objektverhalten. Welche Struktur ist am übersichtlichsten?
  1. Eine Klasse für jede mögliche Temperatur.
  2. Eine Klasse, die jeden Rechenschritt enthält.
  3. Mehrere Objekte mit einem gemeinsamen Ergebnis.
  4. Eine Funktion, die das Umrechnungsergebnis zurückgibt.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Ein Verleihsystem hat viele Fahrräder. Jedes Fahrrad hat eine Bezeichnung und einen Verfügbarkeitszustand sowie dieselben geprüften Aktionen zum Ausleihen und Zurückgeben. Was ist ein nützlicher Klassenentwurf?
  1. Eine Klasse Bike mit Zustand und geprüften Methoden.
  2. Eine Klasse pro Bezeichnung mit kopiertem Aktionscode.
  3. Ein Fahrradobjekt mit allen Bezeichnungen als Aliase.
  4. Eine Klasse, die nur print-Anweisungen enthält.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Das Regal muss ein drittes Buch zurückweisen und seine beiden vorhandenen Bücher behalten. Welche Zusicherung deckt nach dem unten abgefangenen Fehler die fehlerhafte Implementierung auf?

class Shelf:
    def __init__(self):
        self.limit = 2
        self.books = []
    def add(self, title):
        self.books.append(title)
        if len(self.books) > self.limit:
            raise ValueError("shelf full")
shelf = Shelf()
shelf.add("Atlas")
shelf.add("Birch")
try:
    shelf.add("Cove")
except ValueError:
    pass
  1. assert len(shelf.books) == 3
  2. assert shelf.limit == 2
  3. assert len(shelf.books) == 2
  4. assert shelf.books[-1] == "Cove"
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Set 5: Die Ideen in neuen Situationen anwenden10 Übungsfragen

Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.

Frage 1 von 10

Was gibt isinstance(items, list) für eine eingebaute Liste items zurück?
  1. Die Anzahl der Elemente der Liste.
  2. Die Namen ihrer Listenmethoden.
  3. Das Klassenobjekt namens list.
  4. Den booleschen Wert True.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 2 von 10

Was gibt dieser Code aus?

class Tray:
    labels = []
a = Tray()
b = Tray()
a.labels.append("red")
b.labels = ["blue"]
Tray.labels.append("green")
print(a.labels, b.labels)
  1. ['red', 'green'] ['blue']
  2. ['red', 'green'] ['blue', 'green']
  3. ['red'] ['blue', 'green']
  4. ['blue', 'green'] ['blue', 'green']
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 3 von 10

Was gibt dieser Code aus?

class Kit:
    def __init__(self, parts=None):
        self.parts = [] if parts is None else list(parts)
source = [[1]]
k = Kit(source)
source.append([2])
source[0].append(3)
print(k.parts)
  1. [[1]]
  2. [[1, 3], [2]]
  3. [[1, 3]]
  4. [[1], [2]]
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 4 von 10

Der Setter eines Messgeräts weist negative Werte zurück, bevor er _reading speichert. Sein Initialisierer weist direkt an self._reading zu, sodass Meter(-2) gelingt. Welche Änderung sorgt dafür, dass bei der Erstellung dieselbe Prüfung wie bei späteren öffentlichen Zuweisungen verwendet wird?
  1. Dem Getter eine return-Anweisung hinzufügen.
  2. In __init__ mit self.reading = reading zuweisen.
  3. Im Setter mit self.reading = reading zuweisen.
  4. Die Property entfernen und _reading öffentlich lassen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 5 von 10

Ein Key vergleicht Gleichheit nur anhand von name und auch sein Hashwert verwendet name. Zwei verschiedene Instanzen beginnen mit dem Namen "north"; eine wird zu einem Wörterbuchschlüssel. Warum muss der Name dieses Schlüssels stabil bleiben?
  1. Eine Namensänderung ändert die Identitäten beider Objekte.
  2. Alle Instanzattribute müssen in Python unveränderlich sein.
  3. Wörterbuchschlüssel werden beim Einfügen automatisch kopiert.
  4. Ein geänderter Hashwert kann das Nachschlagen des gespeicherten Schlüssels verhindern.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 6 von 10

Zwei Vereine haben jeweils eine separate Liste members, aber beide Listen enthalten dieselbe Instanz von Member. Ein Verein ändert den Namen dieses Mitglieds. Die Vereine benötigen nun unabhängige Mitgliedsnamen. Welche Änderung ist nötig?
  1. Für jeden Verein ein separates Mitgliedsobjekt erstellen.
  2. Nur eine der äußeren Listen members kopieren.
  3. Eine weitere Variable an das gemeinsame Mitglied binden.
  4. members in den Klassenkörper des Vereins verschieben.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 7 von 10

Eine Nachrichtenklasse hat ein nützliches __str__, aber eine ausgegebene Liste von Nachrichten zeigt weiterhin standardmäßige Objektbeschreibungen. Welche Ergänzung verbessert diese Listeneinträge?
  1. Ein __len__, das die Textlänge zurückgibt.
  2. Ein __init__, das den Textwert zurückgibt.
  3. Ein __repr__, das nützlichen Nachrichtentext zurückgibt.
  4. Ein zusätzlicher Aufruf von print innerhalb von __str__.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 8 von 10

a.combine(b) soll beide Eingaben unverändert lassen. Sein Körper ruft self.parts.extend(other.parts) auf und gibt dann self zurück. Welches Verhalten hat diese Implementierung tatsächlich?
  1. Sie erstellt einen neuen Container mit kopierten Teilen.
  2. Sie verändert a und gibt dasselbe Objekt zurück.
  3. Sie verändert b und gibt dasselbe Objekt zurück.
  4. Sie lässt beide unverändert und gibt None zurück.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 9 von 10

Innerhalb von class Vault weist die Einrichtung self.__code = "x" zu. Was erklärt, warum vault.__code scheitert, während vault._Vault__code funktionieren kann?
  1. Der Code wird bei der Initialisierung verschlüsselt.
  2. Die Unterstriche machen den Wert zu einem Klassenattribut.
  3. Der Getter wird nur mit Klammern aufgerufen.
  4. Die Namensumformung ändert den gespeicherten Attributnamen.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Frage 10 von 10

Die Methode take einer Klasse verwendet assert n > 0 als einzige Prüfung der Eingabe des aufrufenden Codes. Die Regel muss auch gelten, wenn Python mit aktivierter Optimierung läuft. Welche Änderung ist nötig?
  1. Das Ergebnis der Zusicherung an den aufrufenden Code zurückgeben.
  2. Die Zusicherung in die aufrufende Schleife verschieben.
  3. Eine ausdrückliche Bedingung verwenden, die eine Ausnahme auslöst.
  4. Die Zusicherung nach der Zustandsaktualisierung platzieren.
Antwort zeigenAntwort ausblenden

Speichere diese Einheit, um diese Antwort zu sehen.

Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe

Schlüsselbegriffe

62 Schlüsselbegriffe, jeweils mit Definition

A

Alias
Ein Alias ist ein weiterer Name, der auf ein vorhandenes Objekt verweist. Änderungen an einem gemeinsam genutzten veränderlichen Objekt können daher über beide Namen gesehen werden.
Nach backup = entries verändert das Anhängen über backup auch die Liste, auf die über entries zugegriffen wird.
Attribut
Ein Attribut ist ein benannter Wert, auf den über ein Objekt oder eine Klasse mit Punktnotation zugegriffen wird, etwa der gespeicherte Titel eines Buches.
Die Zuweisung book.title = "Emma" speichert einen Titel, der anschließend durch Auswertung von book.title gelesen werden kann.
Attributsuche
Die Attributsuche ist der Vorgang, bei dem ein benanntes Attribut gefunden wird; gewöhnliche Instanzdaten können vor einem Klassenwert gefunden werden.
Hat p kein eigenes limit, kann das Lesen von p.limit den gemeinsamen Wert limit finden, der auf seiner Klasse definiert ist.

Ä

Änderungsmethode
Eine Änderungsmethode ist eine Methode, die den Zustand eines vorhandenen Objekts verändert und dabei häufig Eingaben prüft, bevor sie zusammengehörende Attribute aktualisiert.
Eine geprüfte Änderungsmethode für Auszahlungen kann den Kontostand erst verringern und eine Transaktion erfassen, nachdem der Betrag die Validierung bestanden hat.

C

Container
Ein Container ist ein Objekt, das Referenzen auf andere Objekte enthält, sodass diese gemeinsam gespeichert und verarbeitet werden können.
Die Artikelliste eines Einkaufswagens enthält Artikelobjekte; über cart.items[0] erreichst du seinen ersten gespeicherten Artikel.

D

Darstellung für die Programmentwicklung
Eine Darstellung für die Programmentwicklung ist der eindeutige, von __repr__ zurückgegebene Text, der bei der Untersuchung und in Containerdarstellungen verwendet wird.
Die Darstellung eines Buches kann "Book('Emma', 'Jane Austen', 1815)" zeigen, einschließlich der Zeichenkettenfelder in Anführungszeichen.
Datentyp
Ein Datentyp ist die Klasse eines Objekts. Er legt fest, welche Operationen es unterstützt und wie sich Werte dieser Art verhalten.
type([2, 5]) gibt die Klasse list zurück und isinstance([2, 5], list) bestätigt, dass der Wert eine Liste ist.
Delegation
Delegation übergibt einen Teil einer Aufgabe an die Methode eines anderen Objekts, sodass dieses Objekt die Regeln für seine eigenen Daten anwenden kann.
Ein Einkaufswagen delegiert jede Zwischensumme an den jeweiligen Artikel und addiert dann die zurückgegebenen Beträge zur Gesamtsumme.

E

Empfängerobjekt
Das Empfängerobjekt steht bei einem Instanzmethodenaufruf vor dem Punkt und wird automatisch als self-Argument der Methode übergeben.
In sender.transfer_to(receiver, 5) empfängt sender den Überweisungsaufruf; das Kontoargument ist das Ziel.
Ersatzdarstellung
Die Ersatzdarstellung ermöglicht der standardmäßigen Zeichenkettenumwandlung, ein eigenes __repr__ zu verwenden, wenn eine Klasse kein eigenes __str__ definiert.
Wird nur __repr__ ergänzt, kann das sowohl print(point) als auch die Darstellung des Punktes in einer ausgegebenen Liste verbessern.

F

flache Kopie
Eine flache Kopie erstellt ein neues äußeres Objekt und behält dabei Referenzen auf dessen vorhandene verschachtelte Objekte, die gemeinsam genutzt bleiben können.
Speichert ein Konto eine Transaktionsliste, kann das mit copy.copy(account) erstellte Konto diese Liste weiterhin mit dem Original teilen.

G

gebundene Methode
Eine gebundene Methode ist ein Methodenobjekt, das sich sowohl die Funktion als auch die Instanz merkt, die beim Methodenaufruf übergeben wird.
r.area liefert eine gebundene Methode; mit Klammern als r.area() wird sie ausgeführt und gibt die berechnete Fläche zurück.

H

Hashbarkeit
Hashbarkeit ermöglicht einem Objekt, als Mengenelement oder Wörterbuchschlüssel zu dienen, indem ein stabiler Hashwert verwendet wird, der mit seiner Gleichheitsregel übereinstimmt.
Eine Klasse, die __eq__ ohne __hash__ definiert, wird nicht hashbar, auch wenn ihre Instanzen in einer Liste funktionieren.
Hauptprogrammschutz
Ein Hauptprogrammschutz prüft, ob ein Modul direkt ausgeführt wird, und verhindert, dass Startaktionen beim Importieren des Moduls ausgeführt werden.
Setze main() unter if __name__ == "__main__":, damit ein anderes Programm die Klassen importieren kann, ohne es zu starten.

I

Identität
Die Identität unterscheidet ein Objekt von jedem anderen Objekt; der Operator is prüft, ob zwei Referenzen auf dasselbe Objekt verweisen.
Für zwei separat erstellte Listen kann a == b gelten, während a is b falsch ist, weil ihre Identitäten verschieden sind.
Initialisierung
Die Initialisierung setzt den Anfangszustand eines neu erstellten Objekts, üblicherweise indem Argumente und Anfangswerte als Attribute gespeichert werden.
Ein Kontoinitialisierer kann den Inhaber speichern, einen Anfangskontostand entgegennehmen und eine leere Transaktionsliste erstellen.
Instanz
Eine Instanz ist ein einzelnes Objekt, das zu einer Klasse gehört und den diesem Objekt zugeordneten Zustand enthält.
Die Aufrufe Book() und Book() erstellen zwei separate Buchinstanzen, obwohl beide denselben Datentyp haben.
Instanzattribut
Ein Instanzattribut wird auf einem bestimmten Objekt gespeichert und gibt dieser Instanz eigene Daten unter dem Namen des Attributs.
Zwei Pizzen können über Zuweisungen auf self jeweils eine andere size und eine separate Belagliste speichern.
Instanzmethode
Eine Instanzmethode ist eine in einer Klasse definierte Funktion, die das Objekt erhält, auf dem sie aufgerufen wird, üblicherweise über ihren ersten Parameter self.
Bei r.area() übergibt Python r an die Methode, damit sie die Breite und Höhe dieses Rechtecks multiplizieren kann.
internes Attribut
Ein internes Attribut ist für die Verwendung innerhalb der Implementierung einer Klasse vorgesehen. Das wird üblicherweise durch einen führenden Unterstrich im Namen signalisiert.
In einer Kontoklasse liest der aufrufende Code eine öffentliche Property balance, während die eigenen Methoden der Klasse das gespeicherte _balance verwalten.
Invariante
Eine Invariante ist eine Regel, die für den gültigen Zustand eines Objekts wahr bleiben muss, auch nach erfolgreichen Änderungen.
Eine Klasse für Punktzahlen kann verlangen, dass jede Punktzahl bei der Einrichtung und bei späteren Zuweisungen zwischen 0 und 100 bleibt.

K

Kapselung
Kapselung hält die Daten eines Objekts und das Verhalten, das sie verwaltet, zusammen und bietet dem aufrufenden Code eine klare Schnittstelle für gültige Änderungen.
Die Einzahlungsmethode eines Kontos prüft den Betrag und aktualisiert den internen Speicher, ohne dass der aufrufende Code die Regel wiederholen muss.
Klasse
Eine Klasse definiert einen Python-Datentyp und stellt eine gemeinsame Definition für die Attribute und das Verhalten ihrer Instanzen bereit.
Eine Klasse Book kann viele Bücher erstellen, die jeweils einen anderen Titel speichern und dieselben Methodendefinitionen nutzen.
Klassenattribut
Ein Klassenattribut wird auf der Klasse gespeichert und kann von Instanzen gefunden werden, die kein verdeckendes Attribut desselben Namens haben.
Eine klassenweite Einstellung MAX_TOPPINGS kann die Standardobergrenze liefern, die über viele verschiedene Pizzaobjekte gelesen wird.
Klassenentwurf
Der Klassenentwurf wählt die Datentypen, Zustände, Aktionen und Gültigkeitsregeln, die nötig sind, um ein Problem mit zusammenarbeitenden Objekten übersichtlich zu modellieren.
Die Planung einer Bibliothek beginnt mit Büchern und Mitgliedern und platziert dann eine Ausleihgrenze in einer Ausleihoperation.
Komposition
Komposition baut ein größeres Objekt aus anderen Objekten auf, die in seinen Attributen oder Sammlungen gespeichert sind, und modelliert eine Hat-ein-Beziehung.
Eine Bibliothek kann Buchobjekte speichern, wobei jedes Buch seinen Titel und Informationen über den aktuellen Entleiher enthält.

M

Methode
Eine Methode ist eine von einer Klasse bereitgestellte Funktion, die auf einem Objekt aufgerufen werden kann, um mit diesem Objekt oder seinen Daten zu arbeiten.
Der Aufruf "cedar".upper() führt eine Zeichenkettenmethode aus, während scores.append(7) eine Methode auf einer Liste ausführt.

N

Namensumformung
Die Namensumformung schreibt Namen im Klassenkörper mit zwei führenden und ohne zwei abschließende Unterstriche so um, dass sie den Klassennamen enthalten.
Innerhalb von Acc wird self.__balance zu _Acc__balance, das unter dem umgeformten Namen zugänglich bleibt.
None
None ist der einzelne Python-Wert für ein fehlendes oder nicht verfügbares Ergebnis und auch für eine Beziehung nützlich, der noch kein Objekt zugewiesen ist.
Ein Buch kann borrower = None speichern, bis ein Mitglied es ausleiht. Daher prüft der Code, ob ein Entleiher vorhanden ist, bevor er dessen Namen liest.
NotImplemented
NotImplemented ist ein spezieller Rückgabewert, der anzeigt, dass eine Vergleichs- oder numerische Methode die übergebenen Operanden nicht unterstützt.
Die Gleichheitsmethode eines Punktes kann für eine Zeichenkette NotImplemented zurückgeben und Python das nicht unterstützte Paar behandeln lassen.

O

Objekt
Ein Objekt ist ein Python-Wert mit einer Identität, einem Datentyp und einem Zustand sowie den Operationen, die sein Datentyp unterstützt.
Die Zeichenkette "hello" und die Liste [2, 5] sind beide Objekte, obwohl ihre Datentypen unterschiedliche Operationen anbieten.
Objektargument
Ein Objektargument übergibt eine Referenz auf eine Instanz an eine Funktion oder Methode und ermöglicht dem aufgerufenen Code, dieses Objekt zu verwenden.
Der Parameter other in p.midpoint(q) verweist auf q, dessen Koordinaten die Methode liest, um ihr Ergebnis zu berechnen.
Operatorüberladung
Die Operatorüberladung definiert die Bedeutung eines Operators für eine Klasse, indem die zugehörige Spezialmethode implementiert wird.
Das __add__ eines Vektors kann bewirken, dass a + b einen neuen Vektor durch Addition ihrer entsprechenden Koordinaten erzeugt.

P

Property
Eine Property bietet methodengesteuerten Zugriff über Attributsyntax. So kann ein Lesezugriff ein Ergebnis berechnen oder eine Zuweisung Prüfungen ausführen.
Das Lesen von student.score kann einen Getter aufrufen und die Zuweisung student.score = 90 einen validierenden Setter ausführen.
Punktnotation
Punktnotation ist die Syntax, die einen Punkt zwischen ein Objekt oder eine Klasse und den Namen eines Attributs setzt, auf das zugegriffen wird.
In cart.items bezeichnet der Name vor dem Punkt das Objekt und der Name danach wählt dessen Attribut items aus.

R

Referenz
Eine Referenz verbindet einen Namen oder gespeicherten Wert mit einem Objekt und ermöglicht mehreren Namen oder Containern, auf dasselbe Objekt zuzugreifen.
Wird ein Artikel in zwei Einkaufswagenlisten abgelegt, nutzen beide denselben Artikel, sodass eine Änderung seines Preises beide berechneten Gesamtsummen beeinflussen kann.
reflektierte Operation
Eine reflektierte Operation ermöglicht dem rechten Operanden, eine Operation zu behandeln, wenn der linke Operand das Paar nicht unterstützt.
Für 3 * vector kann Python das __rmul__ des Vektors verwenden, wenn die Multiplikation ganzer Zahlen diesen Vektor nicht verarbeiten kann.
Rückgabewert
Ein Rückgabewert ist das Objekt, das ein Aufruf an seinen umgebenden Ausdruck liefert und das für Zuweisungen, Berechnungen oder Prüfungen verfügbar ist.
Die Rückgabe der Fläche ermöglicht r1.area() + r2.area(), die Ergebnisse zu addieren, während bloßes Ausgeben jeweils None als Ergebnis lässt.

S

Schlüsselfunktion
Eine Schlüsselfunktion ermittelt für jedes Element den Wert, den eine Sortieroperation vergleichen soll, und wählt damit eine Ordnung für die jeweilige Aufgabe.
Ein Bericht kann sorted(records, key=by_date) aufrufen, ohne die übliche Vergleichsmethode der Datensatzklasse zu ändern.
self
Der Parameter self erhält nach Konvention die aktuelle Instanz und ermöglicht einer Methode, die Attribute dieses Objekts zu lesen oder zu ändern.
In self.owner = owner speichert die linke Seite Daten auf der Instanz und die rechte Seite liest einen lokalen Parameter.
Setter
Ein Setter ist die Methode, die durch eine Zuweisung an eine Property aufgerufen wird und häufig den vorgeschlagenen Wert validiert, bevor sie ihn separat speichert.
Ein Setter für score, der 105 vor der Zuweisung an _score zurückweist, lässt eine zuvor gültige Punktzahl unverändert.
speicherndes Attribut
Ein speicherndes Attribut speichert den von einer Property verwalteten Wert unter einem separaten Namen und verhindert so rekursiven Property-Zugriff.
Ein Getter für score liest _score; eine Speicherung unter score innerhalb des eigenen Setters würde diesen Setter wiederholt aufrufen.
Spezialmethode
Eine Spezialmethode hat einen Namen mit je zwei Unterstrichen auf beiden Seiten und stellt Verhalten für Python-Syntax oder eingebaute Operationen bereit.
Python fordert __str__ an, wenn es ein Objekt in seine lesbare Zeichenkettendarstellung umwandelt, und __len__ für seine Länge.
Standardargument
Ein Standardargument ist ein Wert, der verwendet wird, wenn der aufrufende Code ein Argument für einen Parameter weglässt. Er wird bei der Definition der Funktion oder Methode ausgewertet.
Mit balance=0 im Initialisierer beginnt Account("Rae") bei null, ohne ein Kontostandargument zu übergeben.
Suchergebnis
Ein Suchergebnis kann das vorhandene passende Objekt oder ein spezieller Wert wie None sein, der anzeigt, dass kein Treffer gefunden wurde.
Der aufrufende Code prüft found is not None, bevor er nach einer Artikelsuche im Einkaufswagen found.name liest.

T

tiefe Kopie
Eine tiefe Kopie kopiert ein Objekt und seine verschachtelten Objekte und trennt dadurch verschachtelten veränderlichen Zustand, der bei einer flachen Kopie gemeinsam genutzt bleiben kann.
Speichert ein Konto eine Transaktionsliste, kopiert copy.deepcopy(account) auch diese Liste, sodass das Anhängen an den Verlauf der Kopie das Original unverändert lässt.
TypeError
Ein TypeError meldet, dass eine Operation einen ungeeigneten Datentyp erhalten hat oder mit Argumenten aufgerufen wurde, die ihre Definition nicht akzeptiert.
Die Übergabe von Text an einen numerischen Breitenvergleich löst TypeError aus, weil dieser Vergleich Text und null nicht ordnen kann.

V

Validierung
Die Validierung prüft vor der Übernahme, ob eingehende Daten oder eine angeforderte Änderung die von einer Klasse verlangten Regeln erfüllen.
Ein Rechteck validiert eine numerische Breite, indem es null oder negative Werte zurückweist, bevor es die Abmessung speichert.
ValueError
Ein ValueError meldet, dass ein Argument einen zulässigen Datentyp hat, sein Wert aber nicht von der Operation akzeptiert wird.
Eine numerische Breite von -2 kann ValueError mit der Meldung "width must be positive" auslösen.
veränderlicher Standardwert
Ein veränderlicher Standardwert ist ein veränderbares Standardobjekt, das über mehrere Aufrufe hinweg wiederverwendet werden kann und bei Speicherung oder Änderung unbeabsichtigte gemeinsame Nutzung verursacht.
Wird items=[] direkt gespeichert, können zwei ohne dieses Argument erstellte Objekte auf dieselbe Liste verweisen.
Veränderlichkeit
Veränderlichkeit ist die Fähigkeit eines Objekts, seinen Inhalt zu ändern und dabei dasselbe Objekt mit derselben Identität zu bleiben.
Das Anhängen an eine Liste verändert die vorhandene Liste; die Anwendung von upper() auf eine Zeichenkette gibt eine neue Zeichenkette zurück.
Verantwortlichkeit
Die Verantwortlichkeit einer Klasse ist die klare Aufgabe, der ihre Daten und Methoden dienen. Sie hilft zu entscheiden, welche Verhaltensweisen zusammengehören.
Ein Artikel berechnet seine eigene Zwischensumme, während ein Einkaufswagen Artikel verwaltet und diese Zwischensummen zu einer Gesamtsumme addiert.
Verdeckung
Eine Verdeckung tritt auf, wenn ein eigenes gewöhnliches Datenattribut einer Instanz bei der Suche ein gleichnamiges Klassenattribut verdeckt.
Nach p.limit = 8 ersetzt eine Änderung von Pizza.limit nicht die separate Obergrenze, die bereits auf p gespeichert ist.
Verhaltenstest
Ein Verhaltenstest erstellt Objekte, führt eine Aktion aus und prüft ein beobachtbares Ergebnis, einschließlich des nach zurückgewiesener Eingabe erhaltenen Zustands.
Ein Auszahlungstest fängt den erwarteten Fehler ab und prüft, ob Kontostand und Verlauf weiterhin ihren vorherigen Werten entsprechen.

W

Wahrheitswertauswertung
Die Wahrheitswertauswertung ist die boolesche Auswertung eines Objekts in einer Bedingung; ohne __bool__ führt eine definierte Länge null zum Wert falsch.
Eine leere Wiedergabeliste mit __len__ und ohne eigenes __bool__ führt dazu, dass if playlist: seinen Körper überspringt.
Wertgleichheit
Wertgleichheit vergleicht Objekte anhand aussagekräftiger Daten, üblicherweise definiert mit __eq__, statt dieselbe Objektidentität zu verlangen.
Zwei separate Punkte mit denselben Koordinaten können als gleich gelten und bei einer Zugehörigkeitsprüfung in einer Liste übereinstimmen.

Z

Zeichenkettendarstellung
Eine Zeichenkettendarstellung ist der von __str__ zurückgegebene lesbare Text, der normalerweise für die Benutzer des Programms bestimmt ist.
Ein Punkt kann bei direkter Ausgabe als "(3, 4)" angezeigt werden, während seine numerischen Koordinatenattribute unverändert bleiben.
Zugriffsmethode
Eine Zugriffsmethode ist eine Methode, die Informationen über den Zustand eines Objekts liefert, ohne diesen Zustand absichtlich zu ändern.
Die Zugriffsmethode area() eines Rechtecks liest seine Breite und Höhe und gibt eine Zahl zurück, ohne seine Größe zu ändern.
Zusicherung
Eine Zusicherung ist eine Entwicklungsprüfung, die AssertionError auslöst, wenn ihre Bedingung falsch ist; Python kann sie bei optimierter Ausführung auslassen.
Nach einer Einzahlung prüft assert acct.balance == 75 das Verhalten; zurückgewiesene Eingaben des aufrufenden Codes benötigen weiterhin ausdrückliche Validierung.
Zustand
Der Zustand eines Objekts besteht aus den aktuellen Daten in seinen Attributen, die Methoden während der Programmausführung untersuchen und aktualisieren können.
Nach einer akzeptierten Einzahlung auf ein Konto mit Verlauf umfasst der Zustand des Kontos sowohl den neuen Kontostand als auch den hinzugefügten Verlaufseintrag.

#

__init__
Die Methode __init__ initialisiert eine Instanz, nachdem Python sie erstellt hat, und muss nach Abschluss der Initialisierung None zurückgeben.
Der Aufruf Counter(5) übergibt die neue Instanz und 5 an ihren Initialisierer, bevor er den eingerichteten Zähler zurückgibt.
__lt__
Die Methode __lt__ implementiert den Kleiner-als-Vergleich und stellt eine Ordnung bereit, die Operationen wie sorted verwenden können.
Ein auf Punktzahlen beruhendes __lt__ ermöglicht, eine Liste von Studierendenobjekten von der niedrigsten bis zur höchsten Punktzahl zu sortieren.

Über diese Einheit

Von StudeliFehler melden

Erstelle deine eigenen Lernmaterialien

Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.

Jetzt starten