Exception in Tkinter callback Traceback (most recent call last): File "C:\Python24\lib\lib-tk\Tkinter.py", line 1345, in __call__ return self.func(*args) TypeError: <lambda>() takes exactly 1 argument (0 given)
I got this error when trying to send command = lambda x: self.adddigit('1') to makeButton - and for all of the rest of the digits, too. The way I fixed it was to again put *x in from of the x in lambda - but I left it out in the key binding. The reason it needs that is because the key binding sends a Tkinter instance, event, to the second argument whereas the button command does not. So to allow for both of them to use the same adddigit function I had to let the lambda in the buttons to accept extra junk. I think. I also took out the list self.bl due to the fact that I am no longer using the list of lambdas in more than one place. (I'm not sure I was before either) Oh, I get your whitespace and readibility thing too. *grin* Here's the code again. ###Start of Calculator.py### from __future__ import division from Tkinter import * class Application(Frame): def ctb(self): if self.shouldblank: self.distext.set('') self.shouldblank = False def adddigit(self, digit): self.ctb() self.distext.set(self.distext.get()+digit) def adddigitdot(self): if not self.distext.get().count('.'): self.ctb() self.distext.set(self.distext.get()+'.') def equal(self): if self.action: self.newnum = self.distext.get() self.newnum = str(eval(self.oldnum+self.action+self.newnum)) self.distext.set(self.newnum) self.oldnum = '0' self.action = '' self.shouldblank = True def add(self): self.handleOperator('+') def subtract(self): self.handleOperator('-') def multiply(self): self.handleOperator('*') def divide(self): self.handleOperator('/') def handleOperator(self, oper): if self.action: self.equal() self.oldnum = self.distext.get() self.action = oper else: self.oldnum = self.distext.get() self.action = oper self.shouldblank = True def clear(self): self.action = '' self.oldnum = '0' self.distext.set('0') self.shouldblank = True def memrecall(self): self.distext.set(self.memory) self.shouldblank = True def memminus(self): self.memory = str(eval(self.memory+"-"+self.distext.get())) self.shouldblank = True def memplus(self): self.memory = str(eval(self.memory+"+"+self.distext.get())) self.shouldblank = True def makeButton(self, text, command, row, column): button = Button(self,text=text,command=command,width=4,height=3) button.grid(row=row,column=column) if len(text) == 1: self.bind_all(text,lambda x: command()) def createWidgets(self): self.distext = StringVar() self.display =Entry(self,textvariable=self.distext,width=22,justify='right') self.display.grid(row=0,column=1,columnspan=4) self.makeButton(text='0',command=lambda *x: self.adddigit('0'),row=5,column=1) self.makeButton(text='1',command=lambda *x: self.adddigit('1'),row=4,column=1) self.makeButton(text='2',command=lambda *x: self.adddigit('2'),row=4,column=2) self.makeButton(text='3',command=lambda *x: self.adddigit('3'),row=4,column=3) self.makeButton(text='4',command=lambda *x: self.adddigit('4'),row=3,column=1) self.makeButton(text='5',command=lambda *x: self.adddigit('5'),row=3,column=2) self.makeButton(text='6',command=lambda *x: self.adddigit('6'),row=3,column=3) self.makeButton(text='7',command=lambda *x: self.adddigit('7'),row=2,column=1) self.makeButton(text='8',command=lambda *x: self.adddigit('8'),row=2,column=2) self.makeButton(text='9',command=lambda *x: self.adddigit('9'),row=2,column=3) self.makeButton(text='.',command=self.adddigitdot,row=5,column=2) self.makeButton(text="=",command=self.equal,row=5,column=3) self.makeButton(text='+',command=self.add,row=5,column=4) self.makeButton(text="-",command=self.subtract,row=4,column=4) self.makeButton(text='x',command=self.multiply,row=3,column=4) self.makeButton(text='/',command=self.divide,row=2,column=4) self.makeButton(text='ON/C',command=self.clear,row=1,column=4) self.makeButton(text='MRC',command=self.memrecall,row=1,column=1) self.makeButton(text="M-",command=self.memminus,row=1,column=2) self.makeButton(text="M+",command=self.memplus,row=1,column=3) def __init__(self, master=None): Frame.__init__(self,master) self.master.title("Calculator by Jacob, Inc.") self.pack(expand=True) self.oldnum = '0' self.memory = '0' self.action = '' self.shouldblank = True self.createWidgets() app = Application() app.mainloop() ###End of Calculator.py### > Jacob S. wrote: > > Great! I took the improvements you gave me an added support for keys (So you > > can type in 1.25+2= instead of having to type the buttons.) As always, I > > encourage improvements to my code. Maybe that will be my disclaimer... I > > have always liked and wanted to adopt Liam's. > > > > Oh, by the way, I'm not trying to make you go blind, it's just I don't tend > > to worry about *my* eyesight and in my subconcious I'm just not considerate > > enough to implement healthy eye habits. sorry... > > I exagerated. I don't really think it is an eye health issue. I do think that careful use of white > space can greatly enhance the readability of your code, which is good for others who might be > reviewing it, and also for you when you come back to it later. > > > Okay, Jacob, reality check -- it's after midnight... > > Here's the code. > > You can simplify the way you add in key bindings. > > First, you don't need to add the *args argument to all the handlers. You know what the argument will > be (an event object) and you don't want to use it, so you can just throw it away in the lambdas. > Kind of the opposite of what I did with adddigit - instead of adding an argument, you throw one away. So > lambda *x: self.adddigit('0',x) > becomes > lambda event: self.adddigit('0') > > There is no need for an extra loop to set up the key bindings. You have all the information you need > in makeButton. It could read like this: > > def makeButton(self, text, command, row, column): > button = Button(self,text=text,command=command,width=4,height=3) > button.grid(row=row,column=column) > if len(text) == 1 > self.bind_all(text,lambda x: command()) > > Or you could pass in an optional argument for the key text so you can bind to 'ON/C' etc. > > Nice work, by the way :-) > > Kent > > > > > ###Start of Calculator.py### > > from __future__ import division > > from Tkinter import * > > > > class Application(Frame): > > def ctb(self): > > if self.shouldblank: > > self.distext.set('') > > self.shouldblank = False > > > > def adddigit(self, digit, *args): > > self.ctb() > > self.distext.set(self.distext.get()+digit) > > > > def adddigitdot(self,*args): > > if not self.distext.get().count('.'): > > self.ctb() > > self.distext.set(self.distext.get()+'.') > > > > def equal(self,*args): > > if self.action: > > self.newnum = self.distext.get() > > self.newnum = str(eval(self.oldnum+self.action+self.newnum)) > > self.distext.set(self.newnum) > > self.oldnum = '0' > > self.action = '' > > self.shouldblank = True > > > > def add(self,*args): > > self.handleOperator('+') > > > > def subtract(self,*args): > > self.handleOperator('-') > > > > def multiply(self,*args): > > self.handleOperator('*') > > > > def divide(self,*args): > > self.handleOperator('/') > > > > > > def handleOperator(self, oper): > > if self.action: > > self.equal() > > self.oldnum = self.distext.get() > > self.action = oper > > else: > > self.oldnum = self.distext.get() > > self.action = oper > > self.shouldblank = True > > > > > > def clear(self): > > self.action = '' > > self.oldnum = '0' > > self.distext.set('0') > > self.shouldblank = True > > > > def memrecall(self): > > self.distext.set(self.memory) > > self.shouldblank = True > > > > def memminus(self): > > self.memory = str(eval(self.memory+"-"+self.distext.get())) > > self.shouldblank = True > > > > def memplus(self): > > self.memory = str(eval(self.memory+"+"+self.distext.get())) > > self.shouldblank = True > > > > > > def makeButton(self, text, command, row, column): > > button = Button(self,text=text,command=command,width=4,height=3) > > button.grid(row=row,column=column) > > > > > > def createWidgets(self): > > self.distext = StringVar() > > self.display > > =Entry(self,textvariable=self.distext,width=22,justify='right') > > self.display.grid(row=0,column=1,columnspan=4) > > > > self.makeButton(text='0',command=self.bl[0],row=5,column=1) > > self.makeButton(text='1',command=self.bl[1],row=4,column=1) > > self.makeButton(text='2',command=self.bl[2],row=4,column=2) > > self.makeButton(text='3',command=self.bl[3],row=4,column=3) > > self.makeButton(text='4',command=self.bl[4],row=3,column=1) > > self.makeButton(text='5',command=self.bl[5],row=3,column=2) > > self.makeButton(text='6',command=self.bl[6],row=3,column=3) > > self.makeButton(text='7',command=self.bl[7],row=2,column=1) > > self.makeButton(text='8',command=self.bl[8],row=2,column=2) > > self.makeButton(text='9',command=self.bl[9],row=2,column=3) > > self.makeButton(text='.',command=self.adddigitdot,row=5,column=2) > > self.makeButton(text="=",command=self.equal,row=5,column=3) > > self.makeButton(text='+',command=self.add,row=5,column=4) > > self.makeButton(text="-",command=self.subtract,row=4,column=4) > > self.makeButton(text='x',command=self.multiply,row=3,column=4) > > self.makeButton(text='/',command=self.divide,row=2,column=4) > > self.makeButton(text='ON/C',command=self.clear,row=1,column=4) > > self.makeButton(text='MRC',command=self.memrecall,row=1,column=1) > > self.makeButton(text="M-",command=self.memminus,row=1,column=2) > > self.makeButton(text="M+",command=self.memplus,row=1,column=3) > > > > > > def __init__(self, master=None): > > Frame.__init__(self,master) > > self.master.title("Calculator by Jacob, Inc.") > > self.pack(expand=True) > > m = lambda x: self.adddigit(x) > > self.bl = [lambda *x: self.adddigit('0',x), > > lambda *x: self.adddigit('1',x), > > lambda *x: self.adddigit('2',x), > > lambda *x: self.adddigit('3',x), > > lambda *x: self.adddigit('4',x), > > lambda *x: self.adddigit('5',x), > > lambda *x: self.adddigit('6',x), > > lambda *x: self.adddigit('7',x), > > lambda *x: self.adddigit('8',x), > > lambda *x: self.adddigit('9',x)] > > for y in range(10): > > self.bind_all(str(y),self.bl[y]) > > self.bind_all("+",lambda x: self.add(x)) > > self.bind_all("-",lambda x: self.subtract(x)) > > self.bind_all("*",lambda x: self.multiply(x)) > > self.bind_all("/",lambda x: self.divide(x)) > > self.bind_all("=",lambda x: self.equal(x)) > > self.bind_all(".",lambda x: self.adddigitdot(x)) > > self.oldnum = '0' > > self.memory = '0' > > self.action = '' > > self.shouldblank = True > > self.createWidgets() > > > > app = Application() > > app.mainloop() > > ###End of Calculator.py### > > > > > > > > > > > >>My suggestions: > >> > >>- How about some white space! Yikes, you trying to make me go blind? > >>- You don't actually need to save all the buttons to attributes. > >>- Much of the button creation is common - I made a button creating > > > > function and call that. > > > >> Copy / paste is not your friend, it is a danger! Refactor instead of > > > > copying! > > > >>- Now you can get rid of all the adddigit functions by making a single > > > > generic adddigit > > > >> and calling it with a lambda. > >>- The four operation functions are identical except the operator; factor > > > > out handleOperation() > > > >> (Copy / paste is not your friend!) > >> > >>- I didn't put the button generation in a loop, once you strip out the > > > > repeated arguments what is > > > >>left is pretty readable as is. > >> > >>Kent > >> > >> > >>from __future__ import division > >>from Tkinter import * > >> > >>class Application(Frame): > >> def ctb(self): > >> if self.shouldblank: > >> self.distext.set('') > >> self.shouldblank = False > >> > >> def adddigit(self, digit): > >> self.ctb() > >> self.distext.set(self.distext.get()+digit) > >> > >> def adddigitdot(self): > >> if not self.distext.get().count('.'): > >> self.ctb() > >> self.distext.set(self.distext.get()+'.') > >> > >> def equal(self): > >> if self.action: > >> self.newnum = self.distext.get() > >> self.newnum = str(eval(self.oldnum+self.action+self.newnum)) > >> self.distext.set(self.newnum) > >> self.oldnum = '0' > >> self.action = '' > >> self.shouldblank = True > >> > >> def add(self): > >> self.handleOperator('+') > >> > >> def subtract(self): > >> self.handleOperator('-') > >> > >> def multiply(self): > >> self.handleOperator('*') > >> > >> def divide(self): > >> self.handleOperator('/') > >> > >> > >> def handleOperator(self, oper): > >> if self.action: > >> self.equal() > >> self.oldnum = self.distext.get() > >> self.action = oper > >> else: > >> self.oldnum = self.distext.get() > >> self.action = oper > >> self.shouldblank = True > >> > >> > >> def clear(self): > >> self.action = '' > >> self.oldnum = '0' > >> self.distext.set('0') > >> self.shouldblank = True > >> > >> def memrecall(self): > >> self.distext.set(self.memory) > >> self.shouldblank = True > >> > >> def memminus(self): > >> self.memory = str(eval(self.memory+"-"+self.distext.get())) > >> self.shouldblank = True > >> > >> def memplus(self): > >> self.memory = str(eval(self.memory+"+"+self.distext.get())) > >> self.shouldblank = True > >> > >> > >> def makeButton(self, text, command, row, column): > >> button = Button(self,text=text,command=command,width=4,height=3) > >> button.grid(row=row,column=column) > >> > >> > >> def createWidgets(self): > >> self.distext = StringVar() > >> self.display > > > > =Entry(self,textvariable=self.distext,width=22,justify='right') > > > >> self.display.grid(row=0,column=1,columnspan=4) > >> > >> self.makeButton(text='0',command=lambda: > > > > self.adddigit('0'),row=5,column=1) > > > >> self.makeButton(text='1',command=lambda: > > > > self.adddigit('1'),row=4,column=1) > > > >> self.makeButton(text='2',command=lambda: > > > > self.adddigit('2'),row=4,column=2) > > > >> self.makeButton(text='3',command=lambda: > > > > self.adddigit('3'),row=4,column=3) > > > >> self.makeButton(text='4',command=lambda: > > > > self.adddigit('4'),row=3,column=1) > > > >> self.makeButton(text='5',command=lambda: > > > > self.adddigit('5'),row=3,column=2) > > > >> self.makeButton(text='6',command=lambda: > > > > self.adddigit('6'),row=3,column=3) > > > >> self.makeButton(text='7',command=lambda: > > > > self.adddigit('7'),row=2,column=1) > > > >> self.makeButton(text='8',command=lambda: > > > > self.adddigit('8'),row=2,column=2) > > > >> self.makeButton(text='9',command=lambda: > > > > self.adddigit('9'),row=2,column=3) > > > >> self.makeButton(text='.',command=self.adddigitdot,row=5,column=2) > >> self.makeButton(text="=",command=self.equal,row=5,column=3) > >> self.makeButton(text='+',command=self.add,row=5,column=4) > >> self.makeButton(text="-",command=self.subtract,row=4,column=4) > >> self.makeButton(text='x',command=self.multiply,row=3,column=4) > >> self.makeButton(text='/',command=self.divide,row=2,column=4) > >> self.makeButton(text='ON/C',command=self.clear,row=1,column=4) > >> self.makeButton(text='MRC',command=self.memrecall,row=1,column=1) > >> self.makeButton(text="M-",command=self.memminus,row=1,column=2) > >> self.makeButton(text="M+",command=self.memplus,row=1,column=3) > >> > >> > >> def __init__(self, master=None): > >> Frame.__init__(self,master) > >> self.master.title("Calculator by Jacob, Inc.") > >> self.pack(fill='both') > >> self.oldnum = '0' > >> self.memory = '0' > >> self.action = '' > >> self.shouldblank = True > >> self.createWidgets() > >> > >>app = Application() > >>app.mainloop() > >>### End of Calculator.py ### > >> > >> > >> > >>Jacob S. wrote: > >> > >>>Here's the code. If you have time, look it over and give me suggestions > > > > for > > > >>>improvement! > >>>(big toothy grin) > >>> > >>>### Start of Calculator.py ### > >>>from __future__ import division > >>>from Tkinter import * > >>> > >>>class Application(Frame): > >>> def ctb(self): > >>> if self.shouldblank: > >>> self.distext.set('') > >>> self.shouldblank = False > >>> def adddigit0(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'0') > >>> def adddigit1(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'1') > >>> def adddigit2(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'2') > >>> def adddigit3(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'3') > >>> def adddigit4(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'4') > >>> def adddigit5(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'5') > >>> def adddigit6(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'6') > >>> def adddigit7(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'7') > >>> def adddigit8(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'8') > >>> def adddigit9(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'9') > >>> def adddigitdot(self): > >>> if not self.distext.get().count('.'): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'.') > >>> def equal(self): > >>> if self.action: > >>> self.newnum = self.distext.get() > >>> self.newnum = str(eval(self.oldnum+self.action+self.newnum)) > >>> self.distext.set(self.newnum) > >>> self.oldnum = '0' > >>> self.action = '' > >>> self.shouldblank = True > >>> def add(self): > >>> if self.action: > >>> self.equal() > >>> self.oldnum = self.distext.get() > >>> self.action = '+' > >>> else: > >>> self.oldnum = self.distext.get() > >>> self.action = '+' > >>> self.shouldblank = True > >>> def subtract(self): > >>> if self.action: > >>> self.equal() > >>> self.oldnum = self.distext.get() > >>> self.action = '-' > >>> else: > >>> self.oldnum = self.distext.get() > >>> self.action = '-' > >>> self.shouldblank = True > >>> def multiply(self): > >>> if self.action: > >>> self.equal() > >>> self.oldnum = self.distext.get() > >>> self.action = '*' > >>> else: > >>> self.oldnum = self.distext.get() > >>> self.action = '*' > >>> self.shouldblank = True > >>> def divide(self): > >>> if self.action: > >>> self.equal() > >>> self.oldnum = self.distext.get() > >>> self.action = '/' > >>> else: > >>> self.oldnum = self.distext.get() > >>> self.action = '/' > >>> self.shouldblank = True > >>> def clear(self): > >>> self.action = '' > >>> self.oldnum = '0' > >>> self.distext.set('0') > >>> self.shouldblank = True > >>> def memrecall(self): > >>> self.distext.set(self.memory) > >>> self.shouldblank = True > >>> def memminus(self): > >>> self.memory = str(eval(self.memory+"-"+self.distext.get())) > >>> self.shouldblank = True > >>> def memplus(self): > >>> self.memory = str(eval(self.memory+"+"+self.distext.get())) > >>> self.shouldblank = True > >>> > >>> > >>> > >>> def createWidgets(self): > >>> self.distext = StringVar() > >>> self.display = > >>>Entry(self,textvariable=self.distext,width=22,justify='right') > >>> self.display.grid(row=0,column=1,columnspan=4) > >>> > >>> self.b0 = > >>>Button(self,text='0',command=self.adddigit0,width=4,height=3) > >>> self.b0.grid(row=5,column=1) > >>> self.b1 = > >>>Button(self,text='1',command=self.adddigit1,width=4,height=3) > >>> self.b1.grid(row=4,column=1) > >>> self.b2 = > >>>Button(self,text='2',command=self.adddigit2,width=4,height=3) > >>> self.b2.grid(row=4,column=2) > >>> self.b3 = > >>>Button(self,text='3',command=self.adddigit3,width=4,height=3) > >>> self.b3.grid(row=4,column=3) > >>> self.b4 = > >>>Button(self,text='4',command=self.adddigit4,width=4,height=3) > >>> self.b4.grid(row=3,column=1) > >>> self.b5 = > >>>Button(self,text='5',command=self.adddigit5,width=4,height=3) > >>> self.b5.grid(row=3,column=2) > >>> self.b6 = > >>>Button(self,text='6',command=self.adddigit6,width=4,height=3) > >>> self.b6.grid(row=3,column=3) > >>> self.b7 = > >>>Button(self,text='7',command=self.adddigit7,width=4,height=3) > >>> self.b7.grid(row=2,column=1) > >>> self.b8 = > >>>Button(self,text='8',command=self.adddigit8,width=4,height=3) > >>> self.b8.grid(row=2,column=2) > >>> self.b9 = > >>>Button(self,text='9',command=self.adddigit9,width=4,height=3) > >>> self.b9.grid(row=2,column=3) > >>> self.bdot = > >>>Button(self,text='.',command=self.adddigitdot,width=4,height=3) > >>> self.bdot.grid(row=5,column=2) > >>> self.equalsign = > >>>Button(self,text="=",command=self.equal,width=4,height=3) > >>> self.equalsign.grid(row=5,column=3) > >>> self.plussign = > >>>Button(self,text='+',command=self.add,width=4,height=3) > >>> self.plussign.grid(row=5,column=4) > >>> self.minussign = > >>>Button(self,text="-",command=self.subtract,width=4,height=3) > >>> self.minussign.grid(row=4,column=4) > >>> self.timessign = > >>>Button(self,text='x',command=self.multiply,width=4,height=3) > >>> self.timessign.grid(row=3,column=4) > >>> self.divsign = > >>>Button(self,text='/',command=self.divide,width=4,height=3) > >>> self.divsign.grid(row=2,column=4) > >>> self.clearb = > >>>Button(self,text='ON/C',command=self.clear,width=4,height=3) > >>> self.clearb.grid(row=1,column=4) > >>> self.mrc = > >>>Button(self,text='MRC',command=self.memrecall,width=4,height=3) > >>> self.mrc.grid(row=1,column=1) > >>> self.mm = > >>>Button(self,text="M-",command=self.memminus,width=4,height=3) > >>> self.mm.grid(row=1,column=2) > >>> self.mp = > >>>Button(self,text="M+",command=self.memplus,width=4,height=3) > >>> self.mp.grid(row=1,column=3) > >>> > >>> > >>> def __init__(self, master=None): > >>> Frame.__init__(self,master) > >>> self.master.title("Calculator by Jacob, Inc.") > >>> self.pack(fill='both') > >>> self.oldnum = '0' > >>> self.memory = '0' > >>> self.action = '' > >>> self.shouldblank = True > >>> self.createWidgets() > >>> > >>>app = Application() > >>>app.mainloop() > >>>### End of Calculator.py ### > >>> > >>>Is there some way that I could loop over those button definitions? > >>> > >>>proposal - code > >>> > >>>a = """ > >>>def adddigit%s(self): > >>> self.ctb() > >>> self.distext.set(self.distext.get()+'%s') > >>>""" > >>>for i in range(10): > >>> exec a % (i,i) > >>> > >>>Pretty cool, huh? I've got my thinking cap on today! > >>> > >>>Thanks in advance for suggestions, > >>>Jacob > >>> > >>> > >>>_______________________________________________ > >>>Tutor maillist - Tutor@python.org > >>>http://mail.python.org/mailman/listinfo/tutor > >>> > >> > >>_______________________________________________ > >>Tutor maillist - Tutor@python.org > >>http://mail.python.org/mailman/listinfo/tutor > >> > >> > > > > > > > _______________________________________________ > Tutor maillist - Tutor@python.org > http://mail.python.org/mailman/listinfo/tutor > _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor