Frage zu Parametern bei CallBack

Fragen zu Tkinter.
Antworten
PhilM
User
Beiträge: 14
Registriert: Donnerstag 20. Februar 2020, 14:31

Hallo zusammen!
Ich habe ein kleines Programm geschrieben um das Scale-Widget unter tkinter auszuprobieren. Im Widget wird der (Benzin-)Verbrauch eingestellt, danach wird die Reichweite mit einer Tankfüllung berechnet. Klappt soweit, aber ...

def reichweite(self):
try:
stand = float(txtStand.get())
verbrauch = scwert.get()
rweite = stand*100/verbrauch
lb2["text"] = f"{rweite:8.2f}"
except:
lb2["text"] = "error"

rufe ich "reichweite()" vom Scale-Widget aus, wird verlangt die Funktion einen Parameter
rufe ich dieselbe Funktion mit einem Button auf, wird der Parameter als Fehler angezeigt.
Wie kann ich erreichen, das "Reichweite()" von beiden Widgets aus gestartet werden kann?

Vielen Dank für Eure Hilfe
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Erster Schritt wäre, das nackte `except` wegzulöschen und den tatsächlichen Fehler sich anzusehen.

Dann brauchen wir auch den kompletten Code und den wirklichen Fehler, um da was sagen zu können.
Es ist komisch, dass `reichweite` ein self-Argument hat, das aber gar nicht benutzt.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das abfangen von allen Fehlern mit einem allumfassenden try/except ist ein Problem, denn damit verschleierst du dir ganz schnell echte Programmierfehler, statt erwartete Fehler abzufangen. Darum immer die spezifischen erwarteten Ausnahmen angeben.

Wenn dich der Parameter ansonsten nicht interessiert, kannst du mit

Code: Alles auswählen

def reichweite(self, *_args):
     ...
einfach alle zusaetzlichen Argumente abfangen. Und ignorieren. Was der einzelne Unterstrich fuer den werten Leser des Codes klarmacht per Konvention.
Benutzeravatar
__blackjack__
User
Beiträge: 14087
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Wobei da nur ein Argument übergeben wird wenn das als Rückruf vom `scale()` verwendet wird: der aktuelle Wert.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Klar, haette man auch nen default-Argument machen koennen.
PhilM
User
Beiträge: 14
Registriert: Donnerstag 20. Februar 2020, 14:31

Vielen Dank!

Code: Alles auswählen

def reichweite(*_args):
hat geholfen.
Vielleicht könnt Ihr mir noch ein wenig theoretischen Background geben. Ich habe mich ja selbst auch über das "self" als Parameter gewundert, dass ja nirgendwo verwendet wird. Ich habe das ganze aus einem Python-Buch übernommen.

Dort wird bei einer Callback Funktion, die durch ein Button ausgelöst wird, auf Parameter verzichtet also

Code: Alles auswählen

def reichweite()
, dagegen beim Auslösen durch ein Scale-Widget mit self gearbeitet.

Code: Alles auswählen

def reichweite(self)
Beides für sich funktioniert. Kann mir jemand den Unterschied erklären?
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Das zeigt, dass der Autor keine Ahnung von Python- und GUI-Programmierung hat und das didaktisch auch nicht gut rüberbringen kann.
PhilM
User
Beiträge: 14
Registriert: Donnerstag 20. Februar 2020, 14:31

Sirius3 hat geschrieben: Donnerstag 20. Februar 2020, 20:56 Das zeigt, dass der Autor keine Ahnung von Python- und GUI-Programmierung hat und das didaktisch auch nicht gut rüberbringen kann.
Da wirst Du wohl recht haben. Erklärst Du es bitte besser?
Sirius3
User
Beiträge: 18289
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie __blackjack__ schon geschrieben hat, ist der eine Parameter, der dem Callback übergeben wird, die Position. Diese Position `self` zu nennen ist quatsch, sollte besser `position` heißen.
Ein Callback für einen Knopf hat keinen Parameter, weil außer Klick keine Information damit verbunden ist.

Auch anderen Variablennamen im Beispiel sind sehr schlecht gewählt, weil sie Abkürzungen sind, die man vermeiden sollte, weil sie einem nur das Lesen und Verstehen erschweren.
PhilM
User
Beiträge: 14
Registriert: Donnerstag 20. Februar 2020, 14:31

OK - Ähnlichkeitshemmung. In anderen Sprachen ist "self" vordefiniert ... Dann ist die Verwendung von self an dieser Stelle natürlich Quatsch.

Danke!
Benutzeravatar
__blackjack__
User
Beiträge: 14087
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Eigentlich sollte die Signatur so aussehen:

Code: Alles auswählen

def reichweite(txtStand, scwert, lb2, *_args):
    ...
Allerdings mit vernünftigen Namen, ohne kryptische Abkürzungen, und in der Schreibweise den Konventionen bei Python entsprechend (Style Guide for Python Code).

Und `txtStand`, `scwert`, und `lb2` wären nicht auf Modulebene definiert, sondern in einer Funktion oder Methode. Und man würde `functools.partial()` verwenden um die Rückruffunktion zu erstellen, die diese Werte gebunden hat.

Oder man hätte doch ein `self` als erstes Argument wenn man das als Methode in einer Klasse definiert, wo man letztlich bei jeder nicht-trivialen GUI sowieso nicht drum herum kommt.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
PhilM
User
Beiträge: 14
Registriert: Donnerstag 20. Februar 2020, 14:31

Erstmal Danke für die Hinweise.
__blackjack__ hat geschrieben: Freitag 21. Februar 2020, 09:32 Oder man hätte doch ein `self` als erstes Argument wenn man das als Methode in einer Klasse definiert, wo man letztlich bei jeder nicht-trivialen GUI sowieso nicht drum herum kommt.
Da ich Python-Anfänger bin, war mein Beispiel tatsächlich eher trivial. Aber verstehe ich Deine Aussage richtig, dass man bei nicht-trivialen GUI-Anwendungen eine Klasse für das Hauptformular erzeugt und dann eine Instanz davon?
Also in etwa

Code: Alles auswählen

class mainform:
	def __init__(self,...)
	...
	
	main =mainform( ...)
	 
Benutzeravatar
__blackjack__
User
Beiträge: 14087
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PhilM: Das ist IMHO schon an der Grenze von nicht-trivial weil an diese Funktion zwei Callbacks gebunden werden und man bei beiden eine Zwischenfunktion erstellen muss bei denen drei Widgets für den Aufruf gebunden werden.

Zum Codeschnippsel – in etwa. Aber wie gesagt: Es gibt Konventionen. Die Klasse würde eher `MainForm` heissen. Eingerückt wird mit vier Leerzeichen pro Ebene, also nicht wie im Beispiel mit Tabulatorzeichen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
PhilM
User
Beiträge: 14
Registriert: Donnerstag 20. Februar 2020, 14:31

@BlackJack

Nochmals Danke!

Und ich werde mir Mühe geben mit den Konventionen
Antworten