Klassen in Python: objektorientierte Programmierung
==, 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
- 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 verwendestBeschreibe 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 erstellenSchreibe eine class-Anweisung, erstelle daraus mehrere getrennte Objekte und setze und lies ihre Attribute mit Punktnotation.
- Objekte erkennen, die du bereits verwendest
- 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 schreibenDefiniere
__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ählenEntscheide, 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 haltenPrüfe die Argumente eines Konstruktors, löse bei falschen Werten eine klare Ausnahme aus und halte die Regeln ein, die ein Objekt sinnvoll machen.
- Einen Konstruktor mit __init__ und self schreiben
- 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 aufrufenSchreibe Methoden, die mit
selfarbeiten, rufe sie auf Objekten auf und gib Ergebnisse zurück, statt sie auszugeben. - Den Zustand eines Objekts mit Methoden ändernSchreibe 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ützenKennzeichne Attribute mit einem Unterstrich als intern und verwende Properties, um neue Werte zu prüfen oder stets aktuelle Werte zu berechnen.
- Instanzmethoden definieren und aufrufen
- Schreibe Spezialmethoden, mit denen deine Objekte lesbaren Text anzeigen, sich mit
==und<vergleichen lassen und mit Operatoren und eingebauten Funktionen funktionieren.- Objekten lesbare Zeichenkettendarstellungen gebenSchreibe
__str__und__repr__so, dass Objekte beim Ausgeben, Untersuchen oder Speichern in einer Liste nützlichen Text anzeigen. - Objekte mit Operatoren vergleichen und kombinierenDefiniere
__eq__,__lt__,__add__und__len__, damit deine Objekte mit==, beim Sortieren, mit+und mitlen()funktionieren, und entscheide, wann ein Operator klarer ist als eine benannte Methode.
- Objekten lesbare Zeichenkettendarstellungen geben
- 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 enthaltenSpeichere 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 machtBeurteile, 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.
- Objekte erstellen, die andere Objekte enthalten
Klassen in Python einfach erklärt
1Objekte 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;isvergleicht 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
| Ausdruck | Bedeutung |
|---|---|
Book | Das Klassenobjekt, das den Datentyp definiert |
Book() | Ein Aufruf, der eine Instanz erstellt |
b1.title | Der auf diesem Buch gespeicherte Titel |
Book.title | Ein 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
AttributeErroraus; eine falsch geschriebene Zuweisung kann ein neues Attribut erstellen.
2Objekte 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 = namespeichert einen Parameter als Instanzattribut.- Erstelle Listen für einzelne Instanzen bei der Initialisierung; verwende
Nonestatt eines veränderlichen Standardwerts. __init__mussNonezurü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.
| Zuweisung | Was sich ändert |
|---|---|
self.size = size | Daten auf der aktuellen Instanz |
Pizza.count += 1 | Der gemeinsam genutzte Klassenzähler |
p1.MAX_TOPPINGS = 8 | Ein 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
| Ausnahme | Beschriebenes Problem |
|---|---|
ValueError | Eine Eingabe zulässiger Art hat einen unzulässigen Wert |
TypeError | Die 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.
3Objekten 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
selfan 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
Nonezurü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.
4Spezialmethoden 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
| Ausdruck | Angeforderte 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
repran. __repr__kann die standardmäßige Zeichenkettendarstellung liefern;__str__ersetztreprnicht.- Beide Methoden müssen Zeichenketten zurückgeben.
- Verwende
!rin 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 OperandentypenNotImplementedzurü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.
5Programme 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
Nonezurü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
selfund 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.
- 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.
- Bestimme die Regeln: Ein Buch darf nicht bereits ausgeliehen sein und ein Mitglied darf
MAX_LOANS = 3nicht überschreiten. - Setze jede Regel in die Operation, die die Beziehung verändert, etwa
Library.check_out(book, member). - 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
1Von vertrauten Werten zu deiner ersten Klasse
11 Schritte
- 1Einfü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?
- 2BeispielDen 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)) # TrueDie 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. - 3BeispielEine 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) # robintitle()gibt eine neue Zeichenkette zurück. Die Zuweisung speichert dieses Ergebnis unterresult, währendnameweiterhin auf"robin"verweist. Mitname = name.title()würdenamestattdessen auf die zurückgegebene Zeichenkette verweisen. - 4BeispielEine direkte Listenänderung verfolgen
Vergleiche den Zeichenkettenaufruf mit dem Sortieren einer Liste.
values = [4, 2] result = values.sort() print(values) # [2, 4] print(result) # NoneDie Liste selbst ändert sich und der Rückgabewert ist
None. Würdest du das Ergebnis des Aufrufs wiedervalueszuweisen, würde die Listenreferenz dieses Namens durchNoneersetzt. Verwendevalues.sort()allein, wenn du die vorhandene Liste verändern möchtest. - 5HerausforderungWo 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].aundbverweisen auf eine Liste, sodass das Anhängen überbdie Liste verändert, die überaerreichbar ist.centhält eine separate Liste. Die Listen waren anfangs gleich, abera is cwar falsch. - 6TippReferenzen vor dem Nachvollziehen von Änderungen zeichnen
Zeichne für jede separat erstellte Liste einen Kasten. Lass sowohl
aals auchbauf den ersten Kasten undcauf 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.titleliefert ein Methodenobjekt, währendname.title()es ausführt. Klammern können den Unterschied ausmachen, ob du ein Verhalten erhältst oder sein Ergebnis. - 7AnalogieEin 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
Badgekann 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. - 8BeispielDen 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"passstellt einen leeren Körper bereit. Jeder Klassenaufruf erstellt eine Instanz und die Zuweisungen mit Punktnotation speichern Daten auf dem ausgewählten Objekt.first is secondist falsch.first = Badgewürde der Klasse stattdessen einen weiteren Namen geben, ohne eine Instanz zu erstellen. - 9HerausforderungEin 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 namensnmae; sie verändertnamenicht. Das Lesen eines nicht vorhandenen Attributs löstAttributeErroraus, aber die Zuweisung an einen neuen Namen ist erlaubt. Prüfe bei einem überraschenden Leseergebnis die Schreibweise sowohl beim Schreiben als auch beim Lesen. - 10HerausforderungInstanzen und Aliase kombinieren
Arbeite mit
firstundsecondaus dem Besucherausweisbeispiel weiter:copy_name = first copy_name.name = "Noor" print(first.name, second.name)---reveal---
Die Ausgabe ist
Noor Ivo.copy_nameist 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. - 11ZusammenfassungEin 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.
2Objekte mit verlässlichen Anfangsdaten erstellen
14 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungEine Aufgabensammlung einrichten
- 2ErklärungPython einen Initialisierer geben
- 3BeispielEinen Aufruf seinen Parametern zuordnen
- 4HerausforderungDas fehlende Attribut erkennen
- 5BeispielEine optionale Anfangsliste entgegennehmen
- 6TippPrüfen, wie weit die Kopie reicht
- 7ErklärungDaten über die Klasse hinzufügen
- 8BeispielEine verdeckende Zuweisung verfolgen
- 9HerausforderungDen gemeinsamen Zähler korrigieren
- 10ErklärungEine unbrauchbare Obergrenze zurückweisen
- 11BeispielFehler und Fehlerbehandlung wählen
- 12HerausforderungWeist eine Ausgabe die Einrichtung zurück?
- 13HerausforderungBei einem Fehler das vorherige Objekt behalten
- 14ZusammenfassungDie Einrichtung aus Sicht des aufrufenden Codes prüfen
3Zustand über Methoden und Properties steuern
16 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungEinen Bestandszähler nutzbar machen
- 2BeispielMit einer gespeicherten Menge beginnen
- 3ErklärungDas Empfängerobjekt als self übergeben lassen
- 4HerausforderungEin Ergebnis wiederverwendbar machen
- 5BeispielNach Prüfung der Menge Bestand hinzufügen
- 6BeispielEine Entnahme vor der Subtraktion zurückweisen
- 7HerausforderungEine Änderung über einen Alias verfolgen
- 8VerbindungDie richtige Zustandsebene kopieren
- 9ErklärungInterne Speicherung kennzeichnen
- 10BeispielÜber eine Property lesen
- 11BeispielGeprüfte öffentliche Zuweisungen erlauben
- 12HerausforderungEinen rekursiven Setter vermeiden
- 13KernaussageEinen Wert beim Lesen berechnen
- 14HerausforderungEinen Setter mit einem Alias kombinieren
- 15TippDefinition und Aufruf zusammen lesen
- 16ZusammenfassungEine Operation nach der anderen testen
4Objekte für Python-Ausdrücke passend machen
17 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungDie Bedeutung eines Objekts festlegen
- 2BeispielMit einem Punkt beginnen
- 3BeispielText für die Untersuchung ergänzen
- 4HerausforderungDie Darstellung einer Liste vorhersagen
- 5TippIn beiden Darstellungsmethoden Text zurückgeben
- 6BeispielKoordinatenwerte vergleichen
- 7KernaussageNicht unterstützte Vergleiche Python überlassen
- 8HerausforderungKönnen gleiche Paare in eine Menge?
- 9BeispielEine Koordinatenordnung wählen
- 10VerbindungEine Ordnung kann zu einer Aufgabe gehören
- 11BeispielAddieren, ohne die Operanden zu verändern
- 12BeispielBeide Multiplikationsreihenfolgen unterstützen
- 13HerausforderungEin neues Ergebnis von einem Alias unterscheiden
- 14ErklärungDie Länge für eine Sammlung verwenden
- 15HerausforderungDen Zweig bei leerer Warteschlange vorhersagen
- 16TippDie Bedeutung erkennbar halten
- 17ZusammenfassungJeden Ausdruck einzeln prüfen
5Objekte mit klaren Aufgaben verbinden
15 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungEine Bestellung aus kleineren Teilen erstellen
- 2BeispielEiner Position eine eigene Berechnung geben
- 3BeispielPositionen in einer Bestellung speichern
- 4BeispielJede Kostenberechnung delegieren
- 5HerausforderungEine von zwei Bestellungen gemeinsam genutzte Position verfolgen
- 6TippEin fehlendes Suchergebnis abfangen
- 7ErklärungEin Objekt an eine andere Methode übergeben
- 8BeispielEmpfängerobjekt und Ergebnis verfolgen
- 9HerausforderungWo stoppt eine fehlgeschlagene Kombination?
- 10VerbindungAufrufe verfolgen, die zwei Objekte verändern
- 11ErklärungEntscheiden, welches Verhalten zusammengehört
- 12HerausforderungEine Klasse für jedes Produkt vermeiden
- 13BeispielDie geprüfte öffentliche Methode zum Hinzufügen testen
- 14HerausforderungEinen Test für den kombinierten Entwurf wählen
- 15ZusammenfassungEine eigene kleine Zusammenarbeit planen
Klassen in Python: Übungsaufgaben
Set 1: Objekte, Referenzen und verlässliche Einrichtung10 Übungsfragen
Frage 1 von 10
Was gibt dieser Code aus?
label = "cedar"
label.upper()
print(label)
Antwort zeigenAntwort ausblenden
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)
Antwort zeigenAntwort ausblenden
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"
Antwort zeigenAntwort ausblenden
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
Antwort zeigenAntwort ausblenden
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)
Antwort zeigenAntwort ausblenden
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)
Antwort zeigenAntwort ausblenden
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)
Antwort zeigenAntwort ausblenden
"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)
Antwort zeigenAntwort ausblenden
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)
Antwort zeigenAntwort ausblenden
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)
Antwort zeigenAntwort ausblenden
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
self, wenn das Programm panel.area() aufruft?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
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
"12,14" übergibt?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)
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)
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
name durch?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
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
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?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)
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
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?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
__str__ als auch __repr__. Welche Methode liefert den Text einer Instanz, wenn sie in einer ausgegebenen Liste erscheint?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)
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
str(marker) einen TypeError aus, wenn seine Methode __str__ nur print(self.code) aufruft?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Vector definiert __mul__ für vector * number, aber keine reflektierte Multiplikationsmethode. Welche Methode sollte ergänzt werden, um auch number * vector zu unterstützen?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
__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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
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?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)
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?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
Workshop speichert Tool-Objekte in self.tools. Was liest workshop.tools[0].label?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
line.cost() aufruft. Ein Mengenrabatt ändert die Berechnung der Kosten jeder Position. Wohin gehört diese Regel?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))
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
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)?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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
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
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
isinstance(items, list) für eine eingebaute Liste items zurück?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)
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)
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
_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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
__str__, aber eine ausgegebene Liste von Nachrichten zeigt weiterhin standardmäßige Objektbeschreibungen. Welche Ergänzung verbessert diese Listeneinträge?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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
class Vault weist die Einrichtung self.__code = "x" zu. Was erklärt, warum vault.__code scheitert, während vault._Vault__code funktionieren kann?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
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?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe
Schlüsselbegriffe
A
Alias
backup = entries verändert das Anhängen über backup auch die Liste, auf die über entries zugegriffen wird.Attribut
book.title = "Emma" speichert einen Titel, der anschließend durch Auswertung von book.title gelesen werden kann.Attributsuche
p kein eigenes limit, kann das Lesen von p.limit den gemeinsamen Wert limit finden, der auf seiner Klasse definiert ist.Ä
Änderungsmethode
C
Container
cart.items[0] erreichst du seinen ersten gespeicherten Artikel.D
Darstellung für die Programmentwicklung
__repr__ zurückgegebene Text, der bei der Untersuchung und in Containerdarstellungen verwendet wird."Book('Emma', 'Jane Austen', 1815)" zeigen, einschließlich der Zeichenkettenfelder in Anführungszeichen.Datentyp
type([2, 5]) gibt die Klasse list zurück und isinstance([2, 5], list) bestätigt, dass der Wert eine Liste ist.Delegation
E
Empfängerobjekt
self-Argument der Methode übergeben.sender.transfer_to(receiver, 5) empfängt sender den Überweisungsaufruf; das Kontoargument ist das Ziel.Ersatzdarstellung
__repr__ zu verwenden, wenn eine Klasse kein eigenes __str__ definiert.__repr__ ergänzt, kann das sowohl print(point) als auch die Darstellung des Punktes in einer ausgegebenen Liste verbessern.F
flache Kopie
copy.copy(account) erstellte Konto diese Liste weiterhin mit dem Original teilen.G
gebundene Methode
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
__eq__ ohne __hash__ definiert, wird nicht hashbar, auch wenn ihre Instanzen in einer Liste funktionieren.Hauptprogrammschutz
main() unter if __name__ == "__main__":, damit ein anderes Programm die Klassen importieren kann, ohne es zu starten.I
Identität
is prüft, ob zwei Referenzen auf dasselbe Objekt verweisen.a == b gelten, während a is b falsch ist, weil ihre Identitäten verschieden sind.Initialisierung
Instanz
Book() und Book() erstellen zwei separate Buchinstanzen, obwohl beide denselben Datentyp haben.Instanzattribut
self jeweils eine andere size und eine separate Belagliste speichern.Instanzmethode
self.r.area() übergibt Python r an die Methode, damit sie die Breite und Höhe dieses Rechtecks multiplizieren kann.internes Attribut
balance, während die eigenen Methoden der Klasse das gespeicherte _balance verwalten.Invariante
0 und 100 bleibt.K
Kapselung
Klasse
Book kann viele Bücher erstellen, die jeweils einen anderen Titel speichern und dieselben Methodendefinitionen nutzen.Klassenattribut
MAX_TOPPINGS kann die Standardobergrenze liefern, die über viele verschiedene Pizzaobjekte gelesen wird.Klassenentwurf
Komposition
M
Methode
"cedar".upper() führt eine Zeichenkettenmethode aus, während scores.append(7) eine Methode auf einer Liste ausführt.N
Namensumformung
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.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.NotImplemented zurückgeben und Python das nicht unterstützte Paar behandeln lassen.O
Objekt
"hello" und die Liste [2, 5] sind beide Objekte, obwohl ihre Datentypen unterschiedliche Operationen anbieten.Objektargument
other in p.midpoint(q) verweist auf q, dessen Koordinaten die Methode liest, um ihr Ergebnis zu berechnen.Operatorüberladung
__add__ eines Vektors kann bewirken, dass a + b einen neuen Vektor durch Addition ihrer entsprechenden Koordinaten erzeugt.P
Property
student.score kann einen Getter aufrufen und die Zuweisung student.score = 90 einen validierenden Setter ausführen.Punktnotation
cart.items bezeichnet der Name vor dem Punkt das Objekt und der Name danach wählt dessen Attribut items aus.R
Referenz
reflektierte Operation
3 * vector kann Python das __rmul__ des Vektors verwenden, wenn die Multiplikation ganzer Zahlen diesen Vektor nicht verarbeiten kann.Rückgabewert
r1.area() + r2.area(), die Ergebnisse zu addieren, während bloßes Ausgeben jeweils None als Ergebnis lässt.S
Schlüsselfunktion
sorted(records, key=by_date) aufrufen, ohne die übliche Vergleichsmethode der Datensatzklasse zu ändern.self
self erhält nach Konvention die aktuelle Instanz und ermöglicht einer Methode, die Attribute dieses Objekts zu lesen oder zu ändern.self.owner = owner speichert die linke Seite Daten auf der Instanz und die rechte Seite liest einen lokalen Parameter.Setter
score, der 105 vor der Zuweisung an _score zurückweist, lässt eine zuvor gültige Punktzahl unverändert.speicherndes Attribut
score liest _score; eine Speicherung unter score innerhalb des eigenen Setters würde diesen Setter wiederholt aufrufen.Spezialmethode
__str__ an, wenn es ein Objekt in seine lesbare Zeichenkettendarstellung umwandelt, und __len__ für seine Länge.Standardargument
balance=0 im Initialisierer beginnt Account("Rae") bei null, ohne ein Kontostandargument zu übergeben.Suchergebnis
None sein, der anzeigt, dass kein Treffer gefunden wurde.found is not None, bevor er nach einer Artikelsuche im Einkaufswagen found.name liest.T
tiefe Kopie
copy.deepcopy(account) auch diese Liste, sodass das Anhängen an den Verlauf der Kopie das Original unverändert lässt.TypeError
TypeError meldet, dass eine Operation einen ungeeigneten Datentyp erhalten hat oder mit Argumenten aufgerufen wurde, die ihre Definition nicht akzeptiert.TypeError aus, weil dieser Vergleich Text und null nicht ordnen kann.V
Validierung
ValueError
ValueError meldet, dass ein Argument einen zulässigen Datentyp hat, sein Wert aber nicht von der Operation akzeptiert wird.-2 kann ValueError mit der Meldung "width must be positive" auslösen.veränderlicher Standardwert
items=[] direkt gespeichert, können zwei ohne dieses Argument erstellte Objekte auf dieselbe Liste verweisen.Veränderlichkeit
upper() auf eine Zeichenkette gibt eine neue Zeichenkette zurück.Verantwortlichkeit
Verdeckung
p.limit = 8 ersetzt eine Änderung von Pizza.limit nicht die separate Obergrenze, die bereits auf p gespeichert ist.Verhaltenstest
W
Wahrheitswertauswertung
__bool__ führt eine definierte Länge null zum Wert falsch.__len__ und ohne eigenes __bool__ führt dazu, dass if playlist: seinen Körper überspringt.Wertgleichheit
__eq__, statt dieselbe Objektidentität zu verlangen.Z
Zeichenkettendarstellung
__str__ zurückgegebene lesbare Text, der normalerweise für die Benutzer des Programms bestimmt ist."(3, 4)" angezeigt werden, während seine numerischen Koordinatenattribute unverändert bleiben.Zugriffsmethode
area() eines Rechtecks liest seine Breite und Höhe und gibt eine Zahl zurück, ohne seine Größe zu ändern.Zusicherung
AssertionError auslöst, wenn ihre Bedingung falsch ist; Python kann sie bei optimierter Ausführung auslassen.assert acct.balance == 75 das Verhalten; zurückgewiesene Eingaben des aufrufenden Codes benötigen weiterhin ausdrückliche Validierung.Zustand
#
__init__
__init__ initialisiert eine Instanz, nachdem Python sie erstellt hat, und muss nach Abschluss der Initialisierung None zurückgeben.Counter(5) übergibt die neue Instanz und 5 an ihren Initialisierer, bevor er den eingerichteten Zähler zurückgibt.__lt__
__lt__ implementiert den Kleiner-als-Vergleich und stellt eine Ordnung bereit, die Operationen wie sorted verwenden können.__lt__ ermöglicht, eine Liste von Studierendenobjekten von der niedrigsten bis zur höchsten Punktzahl zu sortieren.Über diese Einheit
Erstelle deine eigenen Lernmaterialien
Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.