Mein "richtiger Taschenrechner" Zeigt auch Rechenzeichen an - finde ich sehr praktisch, weil ich die Eingaben editieren kann.kaytec hat geschrieben:doch bei meinem wollte ich nicht, dass die Zeichen +,- etc. im Rechenvorgang zusehen sind, sondern es wie ein richtiger taschenrechener funktioniert.
Probleme mit Variablen und tkinter
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Hallo pystyler !!
Da hast Du recht - habe ja auch ihn gefunden bei meiner Suche nach einem Anstoss, doch ihn kopieren wäre ja nicht gerade eine Anforderung - code zu klauen ist ok, doch wollte ich es halt anders machen und dabei lernen. Es geht nicht um besser oder schlechter, sondern um den Spass an der Sache (intrinsiche Motivation).
Danke für Deine Links - gruss frank
Da hast Du recht - habe ja auch ihn gefunden bei meiner Suche nach einem Anstoss, doch ihn kopieren wäre ja nicht gerade eine Anforderung - code zu klauen ist ok, doch wollte ich es halt anders machen und dabei lernen. Es geht nicht um besser oder schlechter, sondern um den Spass an der Sache (intrinsiche Motivation).
Danke für Deine Links - gruss frank
So - habe es mal eingebaut! Es passiert nicht´s - bekomme aber auch keine Fehlermeldung. Das Entry - Feld wird auch nicht gelöscht ??
gruss und dank frank
Code: Alles auswählen
self.funktasten = Button(self, text=text,width=width, command=lambda text=text:self._make_operator_command)
self.funktasten.grid(row=row, column=column, padx=padx, pady=pady)
self.ausgabe = Entry(self,width=29,justify="right",)
self.ausgabe.grid(row=0, column=0,columnspan=6,pady=10)
def _make_operator_command(self, text):
def operator_command():
self.speicher += self.ausgabe.get() + text
self.ausgabe.delete(0, END)
return operator_command
gruss und dank frank
Erst einmal brauchst Du natürlich das ``lambda`` nicht mehr. Die Funktion soll ja von der neuen Methode erzeugt werden. Und dazu musst Du die auch aufrufen ─ mit dem Text der eingefügt werden soll als Argument.
Der Name `taste` braucht auch nicht an das `Rechner`-Objekt gebunden werden. Ausserdem ist Mehrzahl falsch, der Name ist ja immer nur an *einen* `Button` gebunden. In der Zifferntasten-Schleife ist es das gleiche.
Code: Alles auswählen
taste = Button(..., command=self._make_operator_command(text))
So an den Rest habe ich auch mal versucht einzubauen, doch macht das so Sinn oder geht es noch einfacher ?
gruss und dank frank
Code: Alles auswählen
def make_auswertung(self,text):
def auswerten():
if text =="C":
self.ausgabe.delete(0,END)
self.speicher = ""
self.mspeicher = ""
if text =="%":
self.speicher = self.ausgabe.get()
self.speicher = (self.speicher + "/" + "100" + "*")
self.ausgabe.delete(0,END)
if text =="M":
if self.ausgabe.get() =="":
self.speicher = self.speicher + self.mspeicher
if self.ausgabe.get() !="":
self.mspeicher = self.ausgabe.get()
self.ausgabe.delete(0,END)
self.ausgabe.insert(50,"")
if text =="+/-":
self.vorzeichen = str(float (self.ausgabe.get()) * -1)
self.ausgabe.delete(0,END)
self.ausgabe.insert(50,self.vorzeichen)
if text =="=":
try:
self.speicher = str(eval (self.speicher + self.ausgabe.get()))
self.ausgabe.delete(0,END)
self.ausgabe.insert(50,self.speicher)
self.speicher = ""
except:
self.ausgabe.delete(0,END)
self.speicher = ""
self.ausgabe.insert(50,"E")
return auswerten
Das "verstecken" der Alternativen in einer inneren Funktion und die ganzen ``if``-Abfragen finde ich persönlich unschön. Eine Funktion sollte möglichst nur eine abgegrenzte Funktionalität implementieren. `auswerten()` macht dagegen eine ganze Menge verschiedener Dinge.
So würde ich das machen, ja. Wobei ich wohl auch den Taschenrechner, d.h. die Logik davon, von der GUI trennen würde. Damit man den Taschenrechner selbst, ohne GUI (automatisch) testen kann und eventuell auch die GUI austauschbar ist.
Danke BlackJack !!!
Mir wurde bei einem anderem Programm gesagt:
"Hi kaytec!
Auf den ersten Blick würde ich sagen, dein Programm ist nicht kompliziert, sondern eher etwas zu ausformuliert. Du könntest mit einigen Schleifen sicher recht viel code sparen, da tw. eigentlich immer das selbe machst und nur die Namen austauscht. Zudem kann ich dir für solche Sachen Tix.LabelEntry empfehlen, dann ist's noch kürzer. "
Jetzt habe ich dieses Programm mit schleifen verkürzt - oder habe ich das nicht richtig verstanden?
Das wichtigste ist doch das Auslesen des string mit eval(self.speicher). Der Rest ist doch eigentlich nur für die Eingaben über die Oberfläche und das richtige Einlesen in den string ? Meinst du damit die Trennung von Oberfläche und Berechnung ?
gruss frank
Mir wurde bei einem anderem Programm gesagt:
"Hi kaytec!
Auf den ersten Blick würde ich sagen, dein Programm ist nicht kompliziert, sondern eher etwas zu ausformuliert. Du könntest mit einigen Schleifen sicher recht viel code sparen, da tw. eigentlich immer das selbe machst und nur die Namen austauscht. Zudem kann ich dir für solche Sachen Tix.LabelEntry empfehlen, dann ist's noch kürzer. "
Jetzt habe ich dieses Programm mit schleifen verkürzt - oder habe ich das nicht richtig verstanden?
Das wichtigste ist doch das Auslesen des string mit eval(self.speicher). Der Rest ist doch eigentlich nur für die Eingaben über die Oberfläche und das richtige Einlesen in den string ? Meinst du damit die Trennung von Oberfläche und Berechnung ?
gruss frank
Das mit den Schleifen zum Beseitigen von sich wiederholendem Code hast Du richtig verstanden.
Mit der Trennung meine ich, dass man Taschenrecher-Logik und GUI komplett trennt. Das ist jetzt bei Dir beides sehr eng miteinander verknüpft. Du speicherst zum Beispiel für das Programm wichtige Daten in der GUI (`self.ausgabe`) und die meisten Aktionen machen etwas mit dem internen Zustand des Taschenrechners *und* mit der GUI.
Dadurch lässt sich der Taschenrechner bzw. die einzelnen Funktionen nicht ohne GUI testen. Das macht automatisierte Tests und die Fehlersuche schwierig.
Hier ist mal ein minimales Beispiel eines Rechners ohne GUI, der so ähnlich aufgebaut ist wie Deiner:
Den kann man jetzt interaktiv, oder mit einem Testprogramm ausprobieren:
Und wenn man sicher ist, das alles funktioniert, kann man eine GUI draufsetzen.
Diese Trennung wird umso wichtiger und nützlicher je komplexer die beiden Hälften Programmlogik und GUI werden. Und für einen vernünftigen Rechner müssten beide noch ein wenig komplexer werden. Diese `eval()`-Geschichte ist nämlich alles andere als robust.
Mit der Trennung meine ich, dass man Taschenrecher-Logik und GUI komplett trennt. Das ist jetzt bei Dir beides sehr eng miteinander verknüpft. Du speicherst zum Beispiel für das Programm wichtige Daten in der GUI (`self.ausgabe`) und die meisten Aktionen machen etwas mit dem internen Zustand des Taschenrechners *und* mit der GUI.
Dadurch lässt sich der Taschenrechner bzw. die einzelnen Funktionen nicht ohne GUI testen. Das macht automatisierte Tests und die Fehlersuche schwierig.
Hier ist mal ein minimales Beispiel eines Rechners ohne GUI, der so ähnlich aufgebaut ist wie Deiner:
Code: Alles auswählen
class Calculator(object):
def __init__(self):
self.display = ''
self.expression = ''
def clear(self):
self.display = ''
self.expression = ''
def enter_number(self, number):
self.expression += number
self.display = number
def enter_operator(self, operator):
assert operator in list('+-*/')
self.expression += operator
def evaluate(self):
try:
self.display = eval(self.expression)
except (SyntaxError, ArithmeticError):
self.display = 'Error'
self.expression = self.display
Code: Alles auswählen
In [68]: a = test.Calculator()
In [69]: a.display
Out[69]: ''
In [70]: a.enter_number('42')
In [71]: a.display
Out[71]: '42'
In [72]: a.expression
Out[72]: '42'
In [73]: a.enter_operator('+')
In [74]: a.display
Out[74]: '42'
In [75]: a.expression
Out[75]: '42+'
In [76]: a.enter_number('23')
In [77]: a.expression
Out[77]: '42+23'
In [78]: a.display
Out[78]: '23'
In [79]: a.evaluate()
In [80]: a.display
Out[80]: 65
In [81]: a.expression
Out[81]: 65
Diese Trennung wird umso wichtiger und nützlicher je komplexer die beiden Hälften Programmlogik und GUI werden. Und für einen vernünftigen Rechner müssten beide noch ein wenig komplexer werden. Diese `eval()`-Geschichte ist nämlich alles andere als robust.
Hallo BlackJack !!!
Wäre das eine Trennung ?
gruss und dank frank
Wäre das eine Trennung ?
Code: Alles auswählen
class Calculator(object):
def __init__(self):
self.display = ''
self.expression = ''
def clear(self):
self.display = ''
self.expression = ''
def enter_number(self, number):
self.expression += number
self.display = number
def enter_operator(self, operator):
assert operator in list('+-*/')
self.expression += operator
def evaluate(self):
try:
self.display = eval(self.expression)
except (SyntaxError, ArithmeticError):
self.display = 'Error'
self.display = self.expression
a = Calculator()
a.enter_number(raw_input('Eingabe 1.Zahl: '))
print 'a.display:',a.display
print 'a.expression:',a.expression
a.enter_operator(raw_input('Eingabe +-*/: '))
print 'a.expression:',a.expression
a.enter_number(raw_input('Eingabe 2.Zahl: '))
print 'a.display:',a.display
print 'a.expression:',a.expression
a.evaluate()
print 'a.display:',a.display