**kwargs in __init__() Methode und "self" in Python?
Hey Leute,
ich habe heute begonnen, Kivy zu lernen. Kivy ist ein Python Framework, für plattformübergreifende Apps. Ich bin allerdings noch ein Anfänger in Python und da man für Kivy OOP beherrschen muss. Habe ich mir eben ein paar Tutorials angeschaut und das Konzept von Klassen auch verstanden und schon etwas geübt. Auch das "self" eine Referenz auf die aktuelle Instanz ist habe ich kapiert. Aber wieso kann man aus einer Methode auf die Instanzvariablen nur zugreifen, wenn vor diesen "self" steht?
Und meine zweite Frage ist, wozu bei der Initialisierung der __init__() Methode manchmal noch so ein **kwargs steht. Also hier mal ein Beispielcode:
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.word_list = ["python", "java", "ruby", "javascript"]
self.guess_word = []
self.secret_word = ""
self.remaining_guesses = 6
self.img_path = "img/hangman_{}.png"
self.create_game_layout()
self.new_game()
Das ist jetzt mal nur die __init__() Methode einer MyGrid Klasse die von GridLayout erbt.
Ach ja. Was dieses "super()" bedeutet habe ich auch nicht so ganz verstanden.
Ich wäre sehr sehr dankbar wenn mir jemand helfen könnte. Denn ich will für eine Projektarbeit im Informatikunterricht umbedingt eine Android Kivy App für Hangman programmieren. Aber dafür muss ich diese Themen erst einmal verstehen.
LG Code Snake
3 Antworten
super() ist die Elternklasse von der ererbt wurde, also GridLayout.
kwargs sind keyword(ed) args, also benannte Argumente, wenn Du also beim Aufruf sowas wie n=5 übergibst. Es wird also nicht nach Position (positional) sondern nach Name (name/keyword) übergeben.
Dein Konstruktor (Ctor) nimmt also die keyword args und reicht sie an die Elternklasse durch (**kwargs bezeichnet hier die Gesamtheit aller via Name übergebenen Argumente):
super().__init__(**kwargs)
Rufe Konstruktor der Elternklasse mit keyworded arguments auf.
P.S.: der erste Parameter einer Methode ist eine Referenz auf die Objektinstanz, also das aktuelle Objekt.
P.P.S.: Technisch ist es etwas komplexer, weil die * eigentlich ein packing/unpacking machen, aber das solltest Du Dir vielleicht in Ruhe mal zu Gemüte führen.
Sehr gute Antwort! Und einfach am besten erklärt. Das war eine riesen Hilfe.
Aber wieso kann man aus einer Methode auf die Instanzvariablen nur zugreifen, wenn vor diesen "self" steht?
Der Parameter self verweist auf das Objekt und nur das kennt seine an ihm gebundenen Attribute.
Angenommen, du hast diese Anwendung:
class Person:
def __init__(self, name):
self.name = name
def say_name(self):
print(self.name)
person = Person("Max")
person.say_name()
Ein Objekt vom Typ Person wird erstellt und an dieses ein Attribut name gebunden. Der Aufruf von say_name ist implizit nichts anderes, als ein normaler Funktionsaufruf, bei dem allerdings das Objekt übergeben wird:
say_name(person)
Dieses Objekt wird an den Parameter self gegeben. Gäbe es den Parameter nicht, gäbe es keinen Bezug zum Objektkontext.
Und meine zweite Frage ist, wozu bei der Initialisierung der __init__() Methode manchmal noch so ein **kwargs steht.
Das erlaubt die Übergabe beliebig vieler, benannter Parameter.
Dieses spezielle Parameterfeature kann im Grunde für jede normale Funktion angewandt werden:
def print_data(**arguments):
for key, value in arguments.items():
print(key, value)
print_data(age=82, name="Pete", location="New York")
In deinem Fall dient es dazu, genauso flexibel Argumente aufnehmen zu können, wie auch der Basistyp (GridLayout).
Ach ja. Was dieses "super()" bedeutet habe ich auch nicht so ganz verstanden.
Damit wird auf den Basistyp GridLayout zugegriffen.
Angenommen, du möchtest ein Grid Layout mit drei Spalten und drei Reihen anlegen. Dafür kannst du so vorgehen:
layout = GridLayout(cols=3, rows=3)
da der GridLayout-Typ einen Konstruktor besitzt, der die Übergabe benannter Parameter erlaubt.
Nun hast du dir aber einen eigenen Typ erstellt, der von GridLayout erbt. Der kann bei dieser Implementation:
class MyGrid(GridLayout):
def __init__(self):
# do something ...
erst einmal noch nicht das bieten, was du oben beim normalen GridLayout-Typ nutzen konntest: Du kannst beim Anlegen nicht direkt die Spalten- und Zeilenanzahl angeben. Dafür müssen die Parameter erst übergeben werden.
Restriktiv könnte man erst einmal so vorgehen:
class MyGrid(GridLayout):
def __init__(self, cols, rows):
super().__init__(cols=cols, rows=rows)
layout = MyGrid(3, 3)
Die super-Funktion greift auf den Basistyp zu und ruft dessen Konstruktor auf, um die beiden Werte zu übergeben.
Soweit würde dein Typ aber auch nur ein Setup mit Spalten und Zeilen erlauben. Weitere Werte, die schon beim Anlegen eines Grid Layouts definiert werden könnten (z.B. Abstände zwischen den einzelnen Zellen), werden noch nicht unterstützt. Indem man den gleichen Konstruktor wie der Basistyp anbietet und den Parameter direkt weiterreicht, erhält man dieselbe Flexibilität wie der Basistyp.
class MyGrid(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
layout = MyGrid(cols=3, rows=3, spacing=5)
Also, bei den meisten OO sprachen ist "self" implizit. D.h. Du machst Operationen auf einer Objektinstanz einer Klasse. Bei Python musst Du sagen, dass die auf dem objekt operieren, "self" also "diesem Objekt". Klassenmethoden sind dann die Methoden, die nicht "self" als Parameter nehmen. kwargs sind Argumente, die als Schlüsselwort=Wert-Paare angegeben sind.