@Kaewien: Das ist ein furchtbar langer Quelltext mit ganz viel Code der durch kopieren, einfügen, und leicht verändern entstanden ist. Damit man so etwas nicht machen muss, sondern das den Rechner erledigen lässt, programmiert man doch eigentlich. Immer wenn Du so vorgehst, sollte das ein Warnzeichen sein, dass Du sehr wahrscheinlich etwas falsch machst und eigentlich eine Schleife und/oder eine Funktion schreiben möchtest, statt etwas per kopieren im Texteditor wiederholen zu lassen.
Sternchen-Importe holen alle Namen eines Moduls in das importierende Modul. Bei `tkinter` sind das um die 190 Namen, von denen Du nur einen kleinen Bruchteil verwendest. Wenn man das mit mehr als einem Modul macht, verliert man schnell den Überblick welcher Name eigentlich woher kommt. Ausserdem besteht die Gefahr von Namenskollisionen. Das `tkinter`-Modul importiert man deshalb üblicherweise unter dem Namen `tk` mit ``import tkinter as tk`` und greift dann auf die Objekte in dem Modul über diesen Namen zu. Wenn man Modulinhalte mit Sternchen-Importen zusammen matscht, braucht man sich ja nicht die Mühe zu machen Module zu schreiben.
Namen sollte man möglichst nahe an der Stelle definieren wo sie dann auch verwendet werden. Wenn zwischendurch tausend andere Sachen definiert und gemacht werden, hat man an der Stelle wo der Name dann letztendlich verwendet wird, wieder vergessen wie die Definition aussah und man muss wieder im Quelltext weit zurück gehen um das nachzulesen.
Statt vor einer Funktion einen Kommentar zu schreiben was die Funktion tut, sollte man das als Docstring in die Funktion schreiben.
Die vielen ``if``/``elif``-Zweige in der `hexe()`-Funktion kann man durch ein Wörterbuch ersetzen und sowohl die Funktion als auch das Argument könnten deutlich besser benannt sein:
Code: Alles auswählen
def hex_digit_to_int(hex_digit):
"""Die Funktion :func:`hex_digit_to_int` macht aus einem eingegebenen
Hex-Zeichen eine Zahl.
"""
return {
'0': 0,
'1': 1,
'2': 2,
'3': 3,
'4': 4,
'5': 5,
'6': 6,
'7': 7,
'8': 8,
'9': 9,
'A': 10,
'B': 11,
'C': 12,
'D': 13,
'E': 14,
'F': 15,
}[hex_digit.upper()]
Wie man sieht sind die Zahlen von 0 an aufsteigend. Wenn man also eine Zeichenkette mit den Hex-Ziffern hätte, wäre der Index der Wert der jeweiligen Ziffer, also könne man die übergebene Ziffer auch in so einer Zeichenkette suchen:
Code: Alles auswählen
def hex_digit_to_int(hex_digit):
"""Die Funktion :func:`hex_digit_to_int` macht aus einem eingegebenen
Hex-Zeichen eine Zahl.
"""
return '0123456789ABCDEF'.index(hex_digit.upper())
Oder aber man stützt sich auf die bereits existierende `int()`-Funktion ab:
Code: Alles auswählen
def hex_digit_to_int(hex_digit):
"""Die Funktion :func:`hex_digit_to_int` macht aus einem eingegebenen
Hex-Zeichen eine Zahl.
"""
return int(hex_digit, 16)
Die `hexwandler()`-Funktion ist ziemlich abenteuerlich, um das mal vorsichtig auszudrücken. Als erstes sind da wieder die Namen. Funktionen (und Methoden) werden üblicherweise nach Tätigkeiten benannt, weil die etwas tun, um sie besser von eher passiven Werten unterscheiden zu können. Das Argument der Funktion trägt den Namen einer eingebauten Funktion (`hex()`), was man nicht machen sollte, weil es den Leser verwirren kann.
Die Beschreibung der Funktion im Kommetar stimmt nicht so ganz, weil das Ergebnis eine Zahl ist, keine *Dezimal*zahl. Die Zahl wird normalerweise in der Dezimaldarstellung ausgegeben, also in eine Zeichenkette umgewandelt, aber das ist eben nur die Zeichenkettendarstellung von so einem `int`-Objekt.
Die lokalen Namen in der Funktion sind teilweise auch nicht gut gewählt. Aus `h_len` und `hl` wird beim lesen nicht so leicht ersichtlich wofür die beiden gut sind. Kryptische Abkürzungen sollte man vermeiden. Auch `zwischenerg` sollte man ausschreiben. `hl` wird nicht wirklich benötigt, weil das mit `h_len` initialisiert wird und in der Schleife verringert wird, wärhrend `n` erhöht wird. Man kann den `hl`-Wert als in der Schleife problemlos aus `h_len` und `n` berechnen. `zahl` und `zwischenerg` werden vor der Schleife sinnlos auf 0 gesetzt. Dieser Wert wird nie irgendwo verwendet. Die Potenz von der 16 ist bereits eine Zahl, der `int()`-Aufruf dort ist überflüssig. Ebenso ist das bei den Ausdrücken mit `n` völlig sinnfrei. Zwischenstand:
Code: Alles auswählen
def hex_string_to_int(hex_string):
"""Die Funktion :func:`hex_string_to_int` rechnet eine eingegebene
Hexadezimalzahl in eine Zahl um.
"""
string_length = len(hex_string)
ergebnis = 0
for n in range(1, string_length + 1):
zahl = hex_digit_to_int(hex_string[n - 1:n])
zwischenergebnis = zahl * 16**(string_length - n)
ergebnis = ergebnis + zwischenergebnis
return ergebnis
Programmierer fangen bei 0 an zu zählen. Das `n` von 1 an läuft ist ungewöhnlich, das sollte man ändern und `zwischenergebnis` braucht man auch nicht wirklich. Der Name bringt keinen Erkenntnisgewinn beim Lesen und man bekommt das auch prima ohne in einer Zeile unter:
Code: Alles auswählen
def hex_string_to_int(hex_string):
"""Die Funktion :func:`hex_string_to_int` rechnet eine eingegebene
Hexadezimalzahl in eine Zahl um.
"""
string_length = len(hex_string)
ergebnis = 0
for n in range(string_length):
zahl = hex_digit_to_int(hex_string[n:n + 1])
ergebnis += zahl * 16**(string_length - n - 1)
return ergebnis
Das „slicing“ mit `n` ist jetzt aber ziemlich überflüssig, denn das ist ja im Grunde nichts anderes als das `n`-te Zeichen in `hex_string`. Desweiteren kann man die Potenzrechnung recht einfach beseitigen und durch eine Multiplikation ersetzen und damit dann auch gleich `string_length` einsparen:
Code: Alles auswählen
def hex_string_to_int(hex_string):
"""Die Funktion :func:`hex_string_to_int` rechnet eine eingegebene
Hexadezimalzahl in eine Zahl um.
"""
ergebnis = 0
for n in range(len(hex_string)):
zahl = hex_digit_to_int(hex_string[n])
ergebnis = ergebnis * 16 + zahl
return ergebnis
Nun wird `n` nur noch als Index in `hex_string` verwendet und das ist in Python ein „anti pattern“, weil man ohne den Umweg über einen Index über die Elemente von Sequenzen iterieren kann:
Code: Alles auswählen
def hex_string_to_int(hex_string):
"""Die Funktion :func:`hex_string_to_int` rechnet eine eingegebene
Hexadezimalzahl in eine Zahl um.
"""
ergebnis = 0
for hex_digit in hex_string:
zahl = hex_digit_to_int(hex_digit)
ergebnis = ergebnis * 16 + zahl
return ergebnis
`hex_digit` gibt es nur weil `hex_digit_to_int()` auf jedes Zeichen von `hex_string` angewendet werden muss. Den Namen wird man mit der `map()`-Funktion leicht los, so das man in der Schleife direkt über die Zahlwerte zu den Hex-Ziffern iterieren kann:
Code: Alles auswählen
def hex_string_to_int(hex_string):
"""Die Funktion :func:`hex_string_to_int` rechnet eine eingegebene
Hexadezimalzahl in eine Zahl um.
"""
ergebnis = 0
for zahl in map(hex_digit_to_int, hex_string):
ergebnis = ergebnis * 16 + zahl
return ergebnis
Mit `reduce()` aus dem `functools`-Modul und einem ``lambda``-Ausdruck bekommt man das ganze auch gerade noch so in eine Zeile:
Code: Alles auswählen
def hex_string_to_int(hex_string):
"""Die Funktion :func:`hex_string_to_int` rechnet eine eingegebene
Hexadezimalzahl in eine Zahl um.
"""
return reduce(lambda a, b: a * 16 + b, map(hex_digit_to_int, hex_string), 0)
Allerdings ist das alles überflüssig, weil es ja wie wir aus der `hex_digit_to_int()`-Funktion wissen, die `int()`-Funktion gibt, der man eine Basis als optionales Argument übergeben kann, und die kann damit auch mehr als nur eine Ziffer umwandeln. Man muss sich nur um die leere Zeichenkette noch mal gesondert kümmern:
Code: Alles auswählen
def hex_string_to_int(hex_string):
"""Die Funktion :func:`hex_string_to_int` rechnet eine eingegebene
Hexadezimalzahl in eine Zahl um.
"""
return int(hex_string, 16) if hex_string else 0
Letztendlich absolute Grössen und Positionen mittels `width`- und `height`-Argumenten und `pack()` und ``propagate(0)`` sehe ich bei Dir zum ersten mal. Da muss man erst mal drauf kommen. Hier der Grund warum das keine gute Idee ist:
Mir fehlt da eine Spalte und auch die sichtbaren sind nicht alle gleich ausgerichtet. Man sollte weder Grössen oder Positionen hart vorgeben, noch verhindern das Tk selber dafür sorgen kann, dass alles so viel Platz in der Anzeige bekommt wie es benötigt. Sonst sehen GUIs nur auf den Rechnern auf denen sie erstellt wurden vernünftig aus, oder es kann sogar passieren, dass die GUI nicht mehr bedienbar ist, weil Schaltflächen oder Anzeigeelemente gar nicht dargestellt werden. `grid()` hat Sirius3 ja bereits gezeigt.