Wozu das super()-__init__(**kwargs)?
Bei dem Code im Anhang, der Hangman als Python App mit dem Kivy Framework erstellt, weiß ich nicht wozu man die Zeile mit dem super() braucht. Also warum muss man die **kwargs Argumente an die Basisklasse weitergeben?
class HangmanGame(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.word_list = ["python", "java", "ruby", "javascript", "php"]
self.guess_word = []
self.secret_word = ""
self.remaining_guesses = 6
self.img_path = "img/hangman_{}.png"
self.create_game_layout()
self.new_game()
def create_game_layout(self):
self.orientation = "vertical"
self.image = Image(source=self.img_path.format(0))
self.word_label = Label(text=" ".join(self.guess_word),
font_size="50sp",
halign="center",
valign="middle")
self.remaining_guesses_label = Label(text=f"Remaining guesses: {self.remaining_guesses}")
self.input_label = Label(text="Enter a letter:")
self.input = TextInput(multiline=False)
self.submit_button = Button(text="Submit",
#Hier fehlt was unwichtiges, weil die Frage zu lang war
def new_game(self):
self.secret_word = random.choice(self.word_list)
self.guess_word = ["_"] * len(self.secret_word)
self.remaining_guesses = 6
self.image.source = self.img_path.format(0)
self.input.text = ""
self.word_label.text = " ".join(self.guess_word)
self.remaining_guesses_label.text = f"Remaining guesses: {self.remaining_guesses}"
def check_letter(self, instance):
letter = self.input.text
if letter in self.secret_word:
for i, c in enumerate(self.secret_word):
if c == letter:
self.guess_word[i] = letter
if "_" not in self.guess_word:
self.end_game(True)
else:
self.remaining_guesses -= 1
self.image.source = self.img_path.format(6 - self.remaining_guesses)
self.remaining_guesses_label.text = f"Remaining guesses: {self.remaining_guesses}"
if self.remaining_guesses == 0:
self.end_game(False)
self.input.text = ""
self.word_label.text = " ".join(self.guess_word)
def end_game(self, victory):
message = "Congratulations, you won!" if victory else f"Sorry, the word was {self.secret_word}."
self.remaining_guesses_label.text = message
self.remove_widget(self.input_label)
self.remove_widget(self.input)
self.remove_widget(self.submit_button)
self.add_widget(Button(text="New Game", on_press=self.new_game))
class HangmanApp(App):
def build(self):
Window.clearcolor = (0.5, 0.5, 0.5, 1)
return HangmanGame()
HangmanApp().run()
2 Antworten
Die HangmanGame-Instanz stellt auch ein BoxLayout dar (da sie deren Eigenschaften und Verhaltensweisen erbt). Falls du nun beim Erstellen der HangmanGame-Instanz Eigenschaften vordefinieren möchtest, die durch die Basisklasse umgesetzt werden, wird das durch die Konstruktorimplementation auch unterstützt.
Vergleiche:
class HangmanGame(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
game = HangmanGame(spacing=10)
mit:
class HangmanGame(BoxLayout):
def __init__(self, **kwargs):
pass
game = HangmanGame(spacing=10)
Im ersten Fall kann die Funktionalität der Basisklasse genutzt werden. Die Kindelemente des Layouts erhalten einen Abstand zueinander.
Im zweiten Fall hingegen wird der Parameter nicht weiterverarbeitet, also ignoriert.
Wieso erhalte ich beim Beispiel meines letzten Kommentars dann keine Ausgabe "Flipper"?
Das weiß ich nicht. Aber meine Frage lautet:
Aber wenn man dann die Argumente als kwargs an den Konstruktor von der HangmanGame Klasse übergibt, dann kann der Konstruktor der Basisklasse doch schon darauf zugreifen. Wozu dann das super()?
Wenn ich den Code ausführe und kein Flipper als Ausgabe erhalte, dann weiß ich, dass ich das super() brauche. Warum aber nicht.
Also wird der Wert sonst ignoriert? Ganz sicher?
Aber kann man das nicht auch bei dem zweiten Beispiel in der __init__() Methode der aktuellen Klasse machen? Ich frage nur um mich zu vergewissern.
Also wird der Wert sonst ignoriert? Ganz sicher?
Probier es aus.
Aber kann man das nicht auch bei dem zweiten Beispiel in der __init__() Methode der aktuellen Klasse machen?
Du kannst in der __init__-Methode von HangmanGame die Properties setzen.
Beispiel:
class HangmanGame(BoxLayout):
def __init__(self, **kwargs):
if "spacing" in kwargs:
self.spacing = kwargs["spacing"]
Das bedeutet aber nicht, dass der Wert deswegen sofort genutzt wird. Wenn der Basiskonstruktor neben dem Setzen von Attributen noch bestimmte Aktionen durchführt, müsstest du diese erst nachbilden.
Einfacheres Beispiel:
class Animal:
def __init__(self, **kwargs):
if "name" in kwargs:
self.name = kwargs["name"]
print(self.name)
class Lion(Animal):
def __init__(self, **kwargs):
super().__init__(**kwargs)
class Dolphin(Animal):
def __init__(self, **kwargs):
if "name" in kwargs:
self.name = kwargs["name"]
leo = Lion(name="Leo")
flipper = Dolphin(name="Flipper")
Der Basiskonstruktor hat eine Extralogik implementiert, die die Ausgabe des Namens bewirkt. Der Löwe profitiert davon, da er einfach nur den Basiskonstruktor aufruft. Der Delphin hingegen setzt nur den Namen.
In diesem Fall mag das noch nicht so problematisch zu sein. Den einen print-Aufruf könnte man in Dolphin auch noch ergänzen.
Bei GUI-Komponenten hingegen kommt es durchaus häufiger vor, dass der Konstruktor mehrere Aktionen durchführt, die z.B. das Zeichnen der Komponente triggern oder Events registrieren. Was alles im Konstruktor geschieht, müsstest du ebenso erst einmal in Erfahrung bringen.
In dieser Antwort und in deiner neuesten ist aber ein Widerspruch. Hier sagen Sie:
Du kannst in der __init__-Methode von HangmanGame die Properties setzen. Das bedeutet aber nicht, dass der Wert deswegen sofort genutzt wird. Wenn der Basiskonstruktor neben dem Setzen von Attributen noch bestimmte Aktionen durchführt, müsstest du diese erst nachbilden.
In deiner neuesten Antwort sagten Sie aber immer, dass die Instanzvariablen aus dem Konstruktor gar nicht übergeben werden müssten, da die Basisklasse schon darauf zugreifen könne.
Damit beim instanziieren Deiner Klaswe Argumente für die Basisklasse durchgereicht werden - andernfalls müßtest Du deren Funktionalität replizieren, was das Konzept der Vererbung ad absurdum führen würde.
Aber wenn man dann die Argumente als kwargs an den Konstruktor von der HangmanGame Klasse übergibt, dann kann der Konstruktor der Basisklasse doch schon darauf zugreifen. Wozu dann das super()?