Verstehe den Code nicht

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Kahnbein.Kai
User
Beiträge: 104
Registriert: Mittwoch 24. Juni 2015, 14:12
Wohnort: Bochum

Guten Tag,
ich habe gerade ein Codebeispiel gefunden das ich nicht verstehe, evtl. kann mir das jemand erläutern und Licht in die Dunkelheit bringen.
Es geht um folgenden Post bei stack overflow https://stackoverflow.com/questions/624 ... er-but-got
Der Code ist folgender:

Code: Alles auswählen

from tkinter import *

def callback(text, wid):
    if str.isdigit(text) or not text:
        text = text if text else 0
        if wid == str(entry3):
            n = entry2.get() if entry2.get() else 0
        if wid == str(entry2):
            n = entry3.get() if entry3.get() else 0
        ent1.set(int(n) + int(text))
        return True
    return False

root = Tk()

ent1 = IntVar()

vcmd = (root.register(callback), '%P', '%W')
frame = Frame(root)
frame.pack()

entry1 = Entry(frame, width=5, textvariable=ent1)
entry2 = Entry(frame, width=5, validate='all', validatecommand=vcmd)
entry3 = Entry(frame, width=5, validate='all', validatecommand=vcmd)

entry1.pack(side=LEFT)
entry2.pack(side=LEFT)
entry3.pack(side=LEFT)

root.mainloop()
Der Code ermöglicht nur die Eingabe von den Zeichen 0-9.

Ich verstehe mehrere Zeilen in der Methode Callback nicht.
Es geht los mit:

Code: Alles auswählen

if str.isdigit(text) or not text:
- Laut Python Doku übernimmt die Methode isdigit keine Argumente, warum wird hier die Variable Text übergeben ? Müsste es nicht "text.isdigit()" sein ?
- Laut Python Doku gibt isidigit boolean zurück, warum wird dieser Wert dann in einen String umgewandelt ?
- Warum funktioniert diese If-Abfrage, wird dort nicht ein boolen mit einem String (text) verglichen ?

Code: Alles auswählen

text = text if text else 0
- Diese Zeile verstehe ich auch nicht. Ist das eine Variablenzuweisung mit eingebauter If-Abfrage ? Wenn ja warum, die Variable text, kann ja innerhalb der Zeile nicht geändert werden.
Variable text ist gleich variable text wenn variable text sonst 0 ?


Über ein wenig Aufklärung würde ich mich freuen :)
Gruß Kai
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kahnbein.Kai: Ja, das sollte eigentlich ``text.isdigit()`` heissen. Da wird aber nichts in eine Zeichenkette umgewandelt. Da steht ``str.isdigit(text)`` und nicht ``str(…)`` was etwas in eine Zeichenkette umwandeln würde. Die rufen da die `isdigit()`-Methode auf der *Klasse* `str` auf und übergeben das `str`-Objekt das geprüft werden soll. ``str.isdigit(text)`` ist letztlich das gleiche wie ``text.isdigit()`` *wenn* `text` vom Typ `str` ist. Denn für normale Methoden gilt immer ``obj.method()`` ist das gleiche wie ``type(obj).method(obj)``.

Beim zeiten Code steht auf der rechten Seite der Zuweisung ein bedingter Ausdruck der Form ``a if condition else b`` der zu `a` ausgwertet wird wenn `condition` wahr ist, sonst zu `b`.

Wenn `text` im boole'schen Kontext wahr ist, dann ergibt das `text`, ansonsten 0. `text` ist eine Zeichenkette, und nur die leere Zeichenkette ist ”unwahr”:

Code: Alles auswählen

In [45]: bool("")                                                               
Out[45]: False

In [46]: bool("anything but the empty string")                                  
Out[46]: True

In [47]: text = ""                                                              

In [48]: text if text else 0                                                    
Out[48]: 0

In [49]: text = "42"                                                            

In [50]: text if text else 0                                                    
Out[50]: '42'
Ist nicht wirklich schön das `text` dann mal an eine Zeichenkette und mal an eine ganze Zahl gebunden werden kann. Sauberer wäre ``text = text if text else "0"``. Wenn man sicher ist, dass `text` keinen gültigen ”unwahren” Wert haben darf der nicht durch "0" ersetzt werden soll, kann man auch ``text = text or "0"`` an der Stelle schreiben.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

*-Importe sind schlecht. Wenn die erste wid-Bedingung erfüllt ist, kann die zweite nicht mehr wahr werden, also muß das zweite if ein elif sein.
Alles was eine Funktion braucht, muß sie auch über ihre Argumente bekommen, entry2 und entry2 kommen aber aus dem nichts. Ebenso ent1 wobei da bei dem Namen die 1 keinen Sinn macht, und das ent irgendwie nichts aussagt.
Wenn wid weder das eine noch das andere ist, dann ist n nicht definiert, was dann irgendwann später zu einem NameError führt.

Die Funktion müsste also so aussehen:

Code: Alles auswählen

def callback(entry2, entry3, sumvar, text, wid):
    if not text:
        n = 0
    elif text.isdigit():
        n = int(text)
    else:
        return False
    if wid == str(entry3):
        n += int(entry2.get()) if entry2.get() else 0
    elif wid == str(entry2):
        n += int(entry3.get()) if entry3.get() else 0
    sumvar.set(n)
    return True
Jetzt macht die Funktion aber zwei Dinge auf einmal:
1. Testen, ob der eingegebene Text eine Zahl ist und
2. zwei Zahlen zusammenaddieren.

Das sollte aber zwei Funktionen sein. Die dann zusammen auch viel einfacher sind als die eine:

Code: Alles auswählen

import tkinter as tk
from functools import partial

def validate_int(text):
    return not text or text.isdigit()

def calculate_sum(var1, var2, sumvar, _var, _index, _mode):
    sumvar.set(int(var1.get() or 0) + int(var2.get() or 0))

def main():
    root = tk.Tk()
    sumvar = tk.IntVar(root, 0)
    var1 = tk.StringVar(root)
    var2 = tk.StringVar(root)
    var1.trace_add("write", partial(calculate_sum, var1, var2, sumvar))
    var2.trace_add("write", partial(calculate_sum, var1, var2, sumvar))
    validator = (root.register(validate_int), '%P')
    tk.Entry(root, width=5, textvariable=sumvar).pack(side=tk.LEFT)
    tk.Entry(root, width=5, textvariable=var1, validate='all', validatecommand=validator).pack(side=tk.LEFT)
    tk.Entry(root, width=5, textvariable=var2, validate='all', validatecommand=validator).pack(side=tk.LEFT)
    root.mainloop()
                                       
if __name__ == "__main__":
    main()
Kahnbein.Kai
User
Beiträge: 104
Registriert: Mittwoch 24. Juni 2015, 14:12
Wohnort: Bochum

Vielen Dank für die ausführlichen Antworten, jetzt wird es mir um einiges klarer.

Das ärgert mich das ich mich so verlesen habe str. und str(...). :cry:

Gruß Kai
Antworten