Zum Inhalt
wannacode

Konstruktoren und self

Kurz gesagt: Der Konstruktor in Python ist die Methode __init__, die beim Erzeugen des Objekts läuft und seine Attribute über self füllt.

Problem

Kaffee für 0 €

Du erzeugst ein Produkt, genau wie in der letzten Lektion, und füllst die Felder Zeile für Zeile. Eine Zeile hast du vergessen:

coffee = Product()
coffee.name = "Kaffee"
coffee.quantity = 2
print(f"{coffee.name}: {coffee.price * coffee.quantity} €")
Ausgabe
Kaffee: 0.0 €

Der Kaffee kostet 0 €. Python beschwert sich nicht: Der Preis hat einen Wert, 0.0 aus __init__. Je mehr Felder eine Klasse hat, desto leichter vergisst du eines. Und ein Produkt ohne Preis sollte es gar nicht geben können.

Die Idee

Konstruktor: ohne diese Daten kein Objekt

Eine Klasse kann sagen, was sie braucht, bevor du ein Objekt aus ihr erzeugen kannst. Dafür gibt es den Konstruktor: eine besondere Methode, die bei Product(...) läuft. In Python ist das __init__, das du schon kennst, nur dass es jetzt Parameter nimmt.

shop.py
class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
coffee = Product("Kaffee", 7.50, 2)
print(f"{coffee.name}: {coffee.price * coffee.quantity} €")
Ausgabe
Kaffee: 15.0 €
  • Der Konstruktor heißt __init__ (zwei Unterstriche davor und zwei danach), in jeder Klasse.
  • Sein erster Parameter ist self: das Objekt, das gerade entsteht. Python übergibt es für dich.
  • Die anderen Parameter sind die Daten, ohne die ein Produkt nicht auskommt. Du übergibst sie in den Klammern: Product("Kaffee", 7.50, 2).
  • Er gibt nichts zurück. Product(...) gibt das neue Objekt zurück.

Jetzt kannst du den Preis nicht mehr vergessen. Wenn du zwei Argumente statt drei übergibst, hält das Programm genau in dieser Zeile an:

coffee = Product("Kaffee", 7.50)
Fehler
TypeError: Product.__init__() missing 1 required positional argument: 'quantity'

class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
coffee = Product("Kaffee", 7.50, 2)
print(f"{coffee.name}: {coffee.price * coffee.quantity} €")
Schritt für Schritt, in Worten
  1. Product(...) erzeugt ein neues Objekt. Es hat noch keine Felder: __init__ legt sie an.
  2. __init__ läuft. self ist das neue Objekt, und die Argumente gehen in die Parameter.
  3. self.name = name: vom Parameter in ein neues Feld dieses Objekts.
  4. Dasselbe für Preis und Stückzahl.
  5. __init__ ist fertig, und die Parameter verschwinden. coffee bekommt einen Pfeil auf das fertige Objekt.
  6. Das Objekt kommt schon gefüllt aus Product(...), deshalb ist der Preis nicht 0.

Die Idee

self: das Feld dieses Objekts

In __init__ gibt es zwei Dinge namens name: den Parameter und das Feld. name ist der Parameter. Das Feld ist self.name.

class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity

self ist das Objekt, das gerade entsteht. self.name = name bedeutet „speichere den Parameter name im Feld name dieses Objekts“.

In Python ist self. Pflicht. Ohne es ist name = name nur eine Variable in __init__, und sie verschwindet, sobald __init__ endet. Der Name self ist eine Abmachung, kein Schlüsselwort, aber alle schreiben ihn so.

Probier es aus

Finde den Fehler

Das Programm soll „Tee: 3.2 €“ ausgeben. Stattdessen bricht es mit AttributeError: 'Product' object has no attribute 'name' ab. In welcher Zeile ist der Fehler?

Wähle die Zeile mit dem Fehler.

Die Idee

Und Product() aus der letzten Lektion?

In der letzten Lektion hatte __init__ außer self keine Parameter, deshalb hat Product() funktioniert. Jetzt braucht __init__ drei Argumente, und ohne sie hält das Programm an:

empty = Product()
Fehler
TypeError: Product.__init__() missing 3 required positional arguments: 'name', 'price', and 'quantity'

Genau darum geht es: Ein Produkt ohne Name und Preis lässt sich nicht mehr erzeugen.

Genauer, für Neugierige

Wenn eine Klasse gar kein __init__ hat, funktioniert Product() trotzdem: Python erzeugt ein Objekt ganz ohne Felder. Deshalb werden Felder in Python immer in __init__ angelegt.

Die Idee

Eine Standard-Stückzahl

Die meisten Produkte im Warenkorb kommen einzeln. Jedes Mal 1 zu tippen wird lästig.

In Python hat eine Klasse ein __init__. Statt eines zweiten Konstruktors bekommt der Parameter einen Standardwert: Wenn du keine Stückzahl übergibst, ist sie 1.

class Product:
def __init__(self, name, price, quantity=1):
self.name = name
self.price = price
self.quantity = quantity

quantity=1 (ohne Leerzeichen um =) bedeutet „wenn keine Stückzahl übergeben wird, nimm 1“. Parameter mit Standardwert stehen am Ende. Wenn du nach quantity=1 einen Parameter ohne Standardwert schreibst, führt Python die Datei nicht aus:

Fehler
SyntaxError: parameter without a default follows parameter with a default
Genauer, für Neugierige

Ein zweites __init__ in der Klasse ergibt keinen zweiten Konstruktor. Es ersetzt einfach das erste, ohne Warnung, und Product("Brot", 1.20) bricht ab mit:

Fehler
TypeError: Product.__init__() missing 1 required positional argument: 'quantity'

Deshalb hat Python nur einen Konstruktor. Der Vorteil: Wenn du morgen eine Prüfung des Preises hinzufügst, steht sie an einer Stelle.

Probier es aus

Welcher Konstruktor?

Was gibt das Programm aus?

class Product:
def __init__(self, name, price, quantity=1):
self.name = name
self.price = price
self.quantity = quantity
bread = Product("Brot", 1.20)
milk = Product("Milch", 2.10, 3)
print(bread.quantity, milk.quantity)
Antwort

Probier es aus

Wie heißt der Konstruktor?

Was steht in der Lücke?

class Book:
    def (self, title, author):
        self.title = title
        self.author = author

Übung

Objekte, die vollständig entstehen

Löse die Aufgaben in deinem Editor. Jede Klasse bekommt einen Konstruktor mit Parametern für alle ihre Felder.

1. Person. Eine Klasse Person mit Name und Alter. Erzeuge zwei Personen und gib ihre Daten aus.

Ausgabe
Maria, 34 Jahre
Peter, 19 Jahre

2. Tier. Eine Klasse Animal mit Art und Alter. Erzeuge eine 3 Jahre alte Katze und einen 7 Jahre alten Hund.

Ausgabe
Art: Katze, Alter: 3
Art: Hund, Alter: 7

3. Tanzschritt. Eine Klasse DanceMove mit Name und Dauer in Sekunden. In der Lektion „Instanzmethoden“ lernt der Schritt, sich selbst „auszuführen“.

Ausgabe
moonwalk: 5 Sek.

Weitere Aufgaben

  • Ein Buch mit Konstruktor. Schreib Book aus der letzten Lektion mit einem Konstruktor __init__(self, title, author) neu. Wie viele Zeilen sparst du in dem Code unter der Klasse?
  • Ein Produkt mit Standard-Stückzahl. Product mit quantity=1, wie in der Lektion. Leg eine Liste [Product("Brot", 1.20, 2), Product("Kaffee", 7.50)] an und gib von jedem Name und Stückzahl aus: „Brot x2“, „Kaffee x1“.
  • Buchung. Eine Klasse Booking mit dem Namen des Gastes, der Anzahl der Nächte und dem Preis pro Nacht. Gib aus, was der Aufenthalt kostet: Für 3 Nächte zu 85 € sind das 255 €.

Test

Teste dich

1. Wann läuft __init__?
2. Wie heißt der Konstruktor in Python?
3. Die Klasse hat nur def __init__(self, name, price). Was passiert bei Product()?
4. In __init__ steht self.name = name. Was ist self.name?
5. Wie gibt die Klasse eine Stückzahl von 1, wenn beim Erzeugen keine übergeben wird?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·