> > 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. > > Here's a few thoughts.... :) > > > > > 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 > > > Instead of using text representations of the operators, and eval()ing > a string, why not use the operator module? > > Your operator keys can set self.action to be operator.add, > operator.subtract, etc; then your equal() function becomes > > def equal(self, *args): > if self.action: > self.newnum = self.distext.get() > self.newnum= str(self.action(float(self.oldnum), \ > float(self.newnum))) > self.distext.set(self.newnum) > self.oldnum = '0' > self.action = '' # I'd actually prefer None here... > self.shouldblank = True > > > > > def add(self,*args): > > self.handleOperator('+') > > becomes > > def add(self, *args): > self.handleOperator(operator.add) > > The handleOperator() function can stay the same. > > > > def clear(self): > > self.action = '' > > self.oldnum = '0' > > self.distext.set('0') > > self.shouldblank = True > > As I mentioned in a comment above, I'd prefer to use None for > self.action when it's unset. There's no real practical difference, > but conceptually it's more accurate to use a null-object than to use > an empty string. Minor style point, I know, but you *did* ask for > advice. ;) > > > 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 > > Why use eval() here? You could just as easily do these as > > def memminus(self): > self.memory = str(float(self.memory) - \ > float(self.distext.get())) > self.shouldblank = True > > I try to avoid using eval() wherever possible, which is almost > everywhere. ;) There's a huge security hole in using eval() on > arbitrary strings, and it's not the greatest performance either. > (Each invocation of eval() will generate bytecode and create a code > object that does essentially the same thing as my explicit conversion > code does, so by doing it manually you save a parsing/compiling step.) > You're not eval()ing arbitrary strings here, at least, but it's > still good practice to only use eval() when absolutely necessary. > > > > 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)) > > There's absolutely no point to doing lambda x: somefunc(x) -- all > you're doing is adding an extra layer of function call. You can > replace all of those with something like > > self.bind_all('+', self.add) > > And actually, because I'm not fond of lambda to begin with, I'd > redefine your adddigit() method: > > def make_adddigit_callback(self, digit): > def adddigit(*args): > self.ctb() > self.distext.set(self.distext.get()+digit) > return adddigit > > (You may not need the *args above, if the button callback is expected > to be zero parameters -- I don't use Tkinter, so I'm not sure > offhand.) Then your button bindings can simply be > > self.bl = [ self.make_adddigit_callback('0'), > self.make_adddigit_callback('1'), > self.make_adddigit_callback('2'), > ... ] > > Or even -- > > self.bl = [self.make_adddigit_callback(digit) \ > for digit in '0123456789'] > > Remember, there's nothing particularly special about lambdas -- you > can create and pass around regular named functions, too. Each time > that make_adddigit_callback() is called, it creates and returns a new > function object which captures the current value of 'digit', in > exactly the same way that lambda does. A function object (whether > named with def, or lambda) like this, which captures a variable's > current state, is called a closure. Closures are indispensible for > GUI callbacks like this, and many people automatically turn to lambda > when they want a closure. For me, though, having a proper def > statement somewhere feels clearer. (The merits of lambda vs. def'd > functions are a frequent subject of heated debate on comp.lang.python, > so if you prefer to stick with the lambdas in this case, I'm sure > you'd be able to find plenty of people to support you... ;) ) > > Jeff Shannon > Technician/Programmer > Credit International
I know why people make money programming... ;-) I'm not adverse to any conventional way of getting the project to work. There are only a few exceptions like the proposal in python3 to remove raw_input(). You would have to import sys to get sys.stdin.readlines(). Just odd, quirky, whys. I digress. I think the make a new function idea will work. The only reason I used lambdas is because Kent suggested them when I pointed out that you can't call the functions when defining them in the buttons, so you can't pass parameters. Or so I thought. Yes, I think your idea will work. What am I talking about? Of course your idea will work. ;-) Thanks, Jacob Schmidt _______________________________________________ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor