Seite 1 von 1

Python Klassenvererbung und zwei Konstruktore

Verfasst: Freitag 17. Juli 2020, 20:34
von m.g.o.d
Hallo Zusammen:

Ich habe ein Problem, wo ich seit mehreren Stunden einfach nicht weiterkomme.

Ich habe eine Klasse Alarmingtool mit 7 Methoden, die sauber instanziert wird, alle Werte übergeben bekommt und dann problemlos funktioniert.

Nun wollte ich zu dieser Klasse noch eine GUI bauen und dachte mir, ich erstelle eine Klasse GUI(Alarmingtool), die von Alarmingtool abgeleitet ist. Soweit. sogut. Jetzt macht mich der Konstruktor von der 2. Klasse GUI verrückt. Bisher:

Code: Alles auswählen

class Alarmingtool:
	def __init__(self, sql_commercial_promo, sql_deisgn, sql_cornerbug, alarm_commercial_in, alarm_cornerbug_in, alarm_cornerbug_out, alarm_design_in, channelname, adbreak):
		self.SQL_commercial_promo = sql_commercial_promo
		self.SQL_design =  sql_design
		self.SQL_cornerbug = sql_cornerbug
		self.Channelname = channelname
		self.commercial_in = []
		self.cornerbug_in = []
		self.cornerbug_out = []
		...usw
Wenn ich die Klasse instanziere, funktioniert alles soweit. Die Belegung spare ich mir, da sie zuviel Platz bräuchte. Jede Variable erhält jedenfalls einen gültigen Wert bzw. String.

Code: Alles auswählen

DMAX = Alarmingtool(dmax_commercial_promo, dmax_design, dmax_cornerbug, alarm_dmax_commercial_in, alarm_dmax_cornerbug_in, alarm_dmax_cornerbug_out, alarm_dmax_design_in, channelname="DMAXHD", adbreak="DMAX WERBETRENNER")
JETZT kommt ein Merkwürdiges Problem, sobald ich eine Klasse GUI aufsetzte, den Konstruktor von Alarmingtool übernehmen möchte und einen eigenen Konstruktor für GUI setzen will:

Code: Alles auswählen

class GUI(Alarmingtool):
	def__init__(self):		# Konstruktor von GUI (soweit ich verstanden haben)
		super().__init__(self, sql_commercial_promo, sql_deisgn, sql_cornerbug, alarm_commercial_in, alarm_cornerbug_in, alarm_cornerbug_out, alarm_design_in, channelname, adbreak) # Der Konstruktor von Alarmingtool (soweit ich verstanden habe)[/code

Wenn ich nun die Instanzierung dahingehend verändere:
[code]DMAX = GUI(dmax_commercial_promo, dmax_design, dmax_cornerbug, alarm_dmax_commercial_in, alarm_dmax_cornerbug_in, alarm_dmax_cornerbug_out, alarm_dmax_design_in, channelname="DMAXHD", adbreak="DMAX WERBETRENNER")
...kommen für mich nicht nachvollziehbare Fehler, die es nur mit der Klasse Alarmingtool + Instanzierung eben nicht gibt:

Code: Alles auswählen

TypeError: __init__() got an unexpected keyword argument 'channelname'  # Kapiere ich nicht, ich gebe beim Konstruktor von Alarmingtool doch channelname an?!
Ich hoffe ihr könnt mir hier helfen. Also im Klartext: Ich möchte einfach zusätzlich zur (funktionierenden Klasse Alarmingtool) eine Klasse GUI haben, die einen eigenen Konstruktor aufruft und den von Alarmingtool nicht überschreibt (super()....). Aber das haut nicht hin :-( Weiss jemand, weshalb?

Besten Gruß schonmal,
m.g.o.d

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Freitag 17. Juli 2020, 20:40
von m.g.o.d
Achso, wenn ich die Instanzierung auf der Basisklasse lasse, kriege ich stattdessen diesen Fehler:

Code: Alles auswählen

NameError: name 'sql_commercial_promo' is not defined
was noch weniger Sinn macht, weil der Variable einen gültigen String übergeben bekommt und auch im Konstruktor sauber initialisiert wird:

Code: Alles auswählen

self.SQL_commercial_promo = sql_commercial_promo
wenn ich nur folgendes schreibe:

Code: Alles auswählen

super().__init__()
dann erhalte ich den Fehler

Code: Alles auswählen

TypeError: __init__() missing 9 required positional arguments: ....

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Freitag 17. Juli 2020, 21:43
von __blackjack__
@m.g.o.d: Ohne jetzt auf den Rest näher einzugehen ist die Vererbung schon falsch. Vererbung ist eine „ist-ein(e)“-Beziehung. Die GUI für etwas ist aber nicht dieses etwas.

Als nächstes solltest Du die Finger von `super()` lassen. `super()` ist alles andere als Super und macht alles nur unnötig komplizierter. Falls Du `super()` doch verwenden willst, dann muss jede Methode die das verwendet zusätzlich noch beliebige Positions- und Schlüsselwortargumente entgegennehmen und weiterreichen.

Ansonsten wäre es für zukünftige Fragen dieser Art praktisch lauffähigen Code zu sehen der das Problem zeigt und komplette Tracebacks.

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Samstag 18. Juli 2020, 03:27
von m.g.o.d
__blackjack__ hat geschrieben: Freitag 17. Juli 2020, 21:43 @m.g.o.d: Ohne jetzt auf den Rest näher einzugehen ist die Vererbung schon falsch. Vererbung ist eine „ist-ein(e)“-Beziehung. Die GUI für etwas ist aber nicht dieses etwas.

Als nächstes solltest Du die Finger von `super()` lassen. `super()` ist alles andere als Super und macht alles nur unnötig komplizierter. Falls Du `super()` doch verwenden willst, dann muss jede Methode die das verwendet zusätzlich noch beliebige Positions- und Schlüsselwortargumente entgegennehmen und weiterreichen.

Ansonsten wäre es für zukünftige Fragen dieser Art praktisch lauffähigen Code zu sehen der das Problem zeigt und komplette Tracebacks.
Danke für deine Antwort. Mhh okay also wäre es dann besser die GUI in die Hauptklasse zu integrieren und dafür nicht eine extra Klasse abzuleiten?

Ich habe gelesen, dass ohne super()... der Konstruktor der Basisklasse nicht aufgerufen bzw. mit dem Konstruktor von der abgeleiteten Klasse überschrieben wird und dafür eben diese Funktion nötig sei.

Besten Gruß

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Samstag 18. Juli 2020, 07:43
von __blackjack__
@m.g.o.d: Programmlogik und GUI in eine Klasse stecken sollte man auch nicht, beziehungsweise wäre das erben ja letztlich auch genau das. Die GUI ist einfach eine *eigene* Klasse. Die bekommt ein Exemplar der Programmlogik beim erstellen als Argument übergeben und merkt sich das als Attribut.

Die `__init__()` der Basisklasse muss man natürlich aufrufen, aber dazu braucht man kein `super()`, das kann man auch ganz normal über die Basisklasse machen. Lesestoff: Python's Super is nifty, but you can't use it.

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Samstag 18. Juli 2020, 12:30
von kbr
@__blackjack__: Mit dem Artikel gehe ich nicht so ganz konform. Nicht weil die Beispiele falsch wären, denn Python verhält sich tatsächlich so. Sondern weil super() ein Konstrukt ist, das konkret auf die C3-Linearisierung der MRO abgestimmt ist und Proxy-Objekte zurückliefert, die erst zur Laufzeit ermittelt werden. Da kann man nicht einfach anfangen super()-calls und direkte Aufrufe von Methoden aus der Superclass zu mischen, sich dann wundern, dass das nicht funktioniert, um dann zu schlußfolgern, dass super() zwar "nifty" aber nicht brauchbar wäre.

Letztendlich läuft der Artikel darauf hinaus, dass die Verwendung von super() bei Vererbung nicht funktioniert, wenn man es falsch macht. Welch Wunder.

Weiterer Lesestoff für Interessierte wäre https://rhettinger.wordpress.com/2011/0 ... red-super/ der auf die korrekte Verwendung von super() näher eingeht.

Bei Vererbung hört eben der Spaß auf, und bei Mehrfachvererbung erst recht ;)

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Samstag 18. Juli 2020, 13:48
von __blackjack__
@kbr: Mit was gehst Du denn nicht konform? Es ist ja nicht die Trivialität das was nicht funktioniert wenn man es falsch macht, sondern die Kombination aus: das sieht einfach aus, ist aber scheisse kompliziert, so gut wie *jeder* macht's falsch, und es nützt eigentlich sowieso nur bei Mehrfachvererbung mit ”Diamantform” jenseits von einfachen Mixin-Klassen, die aber wiederum niemand verwendet. Das zusammen macht `super()` für mich unbrauchbar und Code einfach nur unnötig aufgebläht und kompliziert wenn ich das einsetzen würde. Und da ich noch nie so eine Diamantform-Vererbung gemacht habe und auch nicht vorhabe so etwas je zu machen, brauche ich das nicht.

Man findet leicht Unmengen von falsch verwendeten `super()`-Aufrufen. Eher wenige korrekte. Wie das geht beschreibt der Artikel den ich verlinkt habe ja auch. Und ich habe bis jetzt noch keinen Fall gesehen wo das tatsächlich Sinn gemacht hätte.

Es ist IMHO einfach irreführend unschuldig. Das fängt ja schon beim Namen an, wo Programmierer die von Java und ähnlichen Sprachen kommen, die ein ``super``kennen, denken sie wüssten was das macht, und es dann nicht korrekt anwenden.

Es ist ja auch nicht nur das mischen, sondern viele die nicht mischen und ”immer” `super()` verwenden, vergessen dann auch gerne, dass man das tatsächlich *immer* anwenden muss. Also auch in der Basisklasse die nur von `object` erbt, muss ein `super.__init(…)`-Aufruf mit allen Argumenten stehen. Das irritiert die Leute die denken das `super()` die ”Superklasse” liefert in der Regel, weil die denken „aber `object` kann doch mit den Argumenten eh nix anfangen“. `super()` verstehen halt sehr viele Leute nicht, denken aber sie würden es verstehen, weil das doch eigentlich ganz einfach ist. Nope.

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Samstag 18. Juli 2020, 19:55
von kbr
@__blackjack__: Was mir an dem Artikel nicht zusagt, hatte ich ja genannt. Er ist mittlerweile auch überarbeitet und entschärft (ob noch eine Kopie der ursprünglichen Version existiert, ist mir nicht bekannt).

Super orientiert sich an der MRO und Methoden werden in Python über den Namen identifiziert, ohne Berücksichtigung der Signatur. Daraus ergibt sich alles weitere. Und ja, das kann dann im Detail kompliziert werden und funktioniert eben nicht genau so, wie es manche von anderen Sprachen gewohnt sein mögen.

Das super() von vielen Leuten nicht richtig verstanden wird, wie Du anmerkst, zweifle ich nicht an. Bei single-Inheritance muß es nicht eingesetzt werden, aber der "falsche" Einsatz von super() schadet dabei üblicherweise auch nicht. So fällt vielen nicht auf, das sich super() unter anderen Umständen anders verhält als gedacht. Aber das macht super() nicht unbrauchbar. Im Gegenteil, es löst Probleme bei multiple-Inheritance. Und wer das nicht weiß, wird den Artikel eher als Polemik gegen super() betrachten und die (mittlerweile hinzugefügten) guten Gründe dafür leicht überlesen.

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Mittwoch 22. Juli 2020, 08:00
von pintman
Könnt ihr ein Beispiel nennen, wo die Verwendung von super() im Falle einer einfachen Vererbung (keine Mehrfachvererbung) zu Problemen oder unintuitivem Verhalten führt?

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Mittwoch 22. Juli 2020, 08:50
von __blackjack__
@pintman: Jain. Im Falle von einfacher Vererbung braucht man es halt nicht. Das Problem ist ja das irgendwann später mal jemand von so einer Klasse ableiten könnte und dann Probleme bekommen kann wenn er Mehrfachvererbung verwendet.

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Mittwoch 22. Juli 2020, 13:01
von kbr
@pintman: Bei einfacher Vererbung wird super() kein "unintuitives" Verhalten zeigen und hat ggf. den Vorteil, dass bei Änderungen der Vererbungshierarchie nicht darauf geachtet werden muß, mögliches "hardwiring" anzupassen. Notwendig aber ist der Einsatz von super() nicht. Wird die Vererbungshierarchie später jedoch komplexer mit Mehrfachvererbung, dann wird "hardwiring" zu Problemen führen – und ein falsch eingesetztes super() auch.

Re: Python Klassenvererbung und zwei Konstruktore

Verfasst: Mittwoch 22. Juli 2020, 13:50
von pintman
Danke für die Klärung. Das deckt sich auch mit meinem Kenntnisstand. :)