Python GUI TypeError: the 'str' object is not callable

advertisements

Ok so I'm supposed to make a basic calculator using GUI in python. I completed that task with all buttons working. Now for step 2, I'm supposed to inherit the original calculator class and create a new class called BetterCalculator, which adds in the buttons sqrt, log, pct, and pow. I have got everything working except for the pow button and when I run the program with what the teacher calls a driver, I get this error:

   Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python33\lib\tkinter\__init__.py", line 1475, in __call__
    return self.func(*args)
  File "E:\calculator\Calculator in class\calculator.py", line 102, in do3
    self.n.set(self.n.get()+'3')
TypeError: 'str' object is not callable

and here is my code:

    #Windows basic built-in interface library.
import tkinter
import math

class Calculator:
    def __init__(self):
        self.win = tkinter.Tk()  # Window object created

# Create frames for buttons. Win frame, topFrame(label, display) \
# bottomFrame (numberFrame

        self.topFrame = tkinter.Frame(self.win)
        self.bottomFrame = tkinter.Frame(self.win)
        self.numbersFrame = tkinter.Frame(self.bottomFrame)
        self.no123Frame = tkinter.Frame(self.numbersFrame)
        self.no456Frame = tkinter.Frame(self.numbersFrame)
        self.no789Frame = tkinter.Frame(self.numbersFrame)
        self.no0DFrame = tkinter.Frame(self.numbersFrame)
        self.optsFrame = tkinter.Frame(self.bottomFrame)

# Create object Label to use for input and output. StringVar is a class.
        self.n = tkinter.StringVar()
# Display object created
        self.display = tkinter.Label(self.topFrame, textvariable = self.n, bg = 'white', font = 12, height = 2, width = 20)
# Number Buttons created. self.b1 = object, tkinter.button calls button module, command = do1 will\
# become a method.
        self.b1 = tkinter.Button(self.no123Frame, width = 3 , text = '1', command = self.do1)
        self.b2 = tkinter.Button(self.no123Frame, width = 3 , text = '2', command = self.do2)
        self.b3 = tkinter.Button(self.no123Frame, width = 3 , text = '3', command = self.do3)
        self.b4 = tkinter.Button(self.no456Frame, width = 3 , text = '4', command = self.do4)
        self.b5 = tkinter.Button(self.no456Frame, width = 3 , text = '5', command = self.do5)
        self.b6 = tkinter.Button(self.no456Frame, width = 3 , text = '6', command = self.do6)
        self.b7 = tkinter.Button(self.no789Frame, width = 3 , text = '7', command = self.do7)
        self.b8 = tkinter.Button(self.no789Frame, width = 3 , text = '8', command = self.do8)
        self.b9 = tkinter.Button(self.no789Frame, width = 3 , text = '9', command = self.do9)
        self.b0 = tkinter.Button(self.no0DFrame, width = 3 , text = '0', command = self.do0)
        self.bD = tkinter.Button(self.no0DFrame, width = 3 , text = '.', command = self.doD)
        self.bCal = tkinter.Button(self.no0DFrame, width = 3 , text = '=', command = self.cal)
# Operators created
        self.bAdd = tkinter.Button(self.optsFrame, width = 5, text = '+', command = self.add)
        self.bSub = tkinter.Button(self.optsFrame, width = 5, text = '-', command = self.sub)
        self.bMul = tkinter.Button(self.optsFrame, width = 5, text = '*', command = self.mul)
        self.bDiv = tkinter.Button(self.optsFrame, width = 5, text = '/', command = self.div)
        self.bMod = tkinter.Button(self.optsFrame, width = 5, text = '%', command = self.mod)
        self.bClr = tkinter.Button(self.topFrame, width = 5, text = 'Clear', command = self.clr)
# Create numbers. op1 = operand, op2 = operator
        op1 = 0.0
        op2 = 0.0
        opt = ''

    def organizeInterface(self):
# Method pack object(assembling display label into window).
# Order of packing will be the order the labels will display.

        self.display.pack(side = 'left')
        self.bClr.pack()
        self.topFrame.pack()

        self.b1.pack(side = 'left')
        self.b2.pack(side = 'left')
        self.b3.pack(side = 'left')
        self.no123Frame.pack()
        self.b4.pack(side = 'left')
        self.b5.pack(side = 'left')
        self.b6.pack(side = 'left')
        self.no456Frame.pack()
        self.b7.pack(side = 'left')
        self.b8.pack(side = 'left')
        self.b9.pack(side = 'left')
        self.no789Frame.pack()
        self.bD.pack(side = 'left')
        self.b0.pack(side = 'left')
        self.bCal.pack(side = 'left')
        self.no0DFrame.pack(side = 'left')
        self.numbersFrame.pack(side = 'left')

        self.bAdd.pack(side = 'left')
        self.bSub.pack(side = 'left')
        self.bDiv.pack(side = 'left')
        self.bMul.pack(side = 'left')
        self.bMod.pack(side = 'left')
        self.optsFrame.pack()
        self.bottomFrame.pack()

    def runInterface(self):
        tkinter.mainloop()

#clear user input.
    def clear(self):
        self.op1 = 0.0
        self.op2 = 0.0
        self.opt = ''

# Set user input, set variable self.n.set then self.n.get will append and concatonate.
    def do1(self):
        self.n.set(self.n.get()+'1')
    def do2(self):
        self.n.set(self.n.get()+'2')
    def do3(self):
        self.n.set(self.n.get()+'3')
    def do4(self):
        self.n.set(self.n.get()+'4')
    def do5(self):
        self.n.set(self.n.get()+'5')
    def do6(self):
        self.n.set(self.n.get()+'6')
    def do7(self):
        self.n.set(self.n.get()+'7')
    def do8(self):
        self.n.set(self.n.get()+'8')
    def do9(self):
        self.n.set(self.n.get()+'9')
    def do0(self):
        self.n.set(self.n.get()+'0')
    def doD(self):
        self.n.set(self.n.get()+'.')

# record operator = self.opt and get first number entry = self.n.get().
# need to clean up the label of the first number entry before getting next \
# entry of numbers.
    def add(self):
        self.opt = '+'
        self.op1 = float(self.n.get())
        self.n.set('')

#to get calculator to see negative number verse \
#subtraction create if statement for empty string.
    def sub(self):
        if self.n.get() == '':
            self.n.set('-')
        else:
            self.opt = '-'
            self.op1 = float(self.n.get())
            self.n.set('')

    def mul(self):
        self.opt = '*'
        self.op1 = float(self.n.get())
        self.n.set('')

    def div(self):
        self.opt = '/'
        self.op1 = float(self.n.get())
        self.n.set('')

    def mod(self):
        self.opt = '%'
        self.op1 = float(self.n.get())
        self.n.set('')

# clear set to clr button to clean label

    def clr(self):
        self.clear()
        self.n.set('')

# Call calculate method to get calculations and write if statements \
# to define what operator user wanted.

    def cal(self):
        self.op2 = float(self.n.get())
        if self.opt == '+':
            self.n.set(self.op1 + self.op2)

        elif self.opt == '-':
            self.n.set(self.op1 - self.op2)

        elif self.opt == '*':
            self.n.set(self.op1 * self.op2)

        elif self.opt == '/':
            self.n.set(self.op1 / self.op2)

        elif self.opt == '%':
            self.n.set(self.op1 % self.op2)

class BetterCalculator(Calculator):
    def __init__(self):
        Calculator.__init__(self)
        self.uOptsFrame = tkinter.Frame(self.bottomFrame)
        self.bLog = tkinter.Button(self.uOptsFrame, width = 5, text = 'log', command = self.log)
        self.bPct = tkinter.Button(self.uOptsFrame, width = 5, text = 'Pct', command = self.pct)
        self.bSqrt = tkinter.Button(self.uOptsFrame, width = 5, text = 'Sqrt', command = self.sqrt)
        self.bPow = tkinter.Button(self.optsFrame, width = 5, text = 'pow', command = self.pow)

    def reorganizeInterface(self):

        self.bClr.configure(bg = 'red')
        self.bAdd.configure(bg = 'yellow')
        self.bSub.configure(bg = 'yellow')
        self.bMul.configure(bg = 'yellow')
        self.bDiv.configure(bg = 'yellow')
        self.bMod.configure(bg = 'yellow')
        self.bCal.configure(bg = 'green')

        Calculator.organizeInterface(self)

        self.bLog.pack()
        self.bPct.pack()
        self.bSqrt.pack()
        self.bPow.pack()
        self.uOptsFrame.pack(side='left')

    def log(self):
        self.op1 = float(self.n.get())
        self.n.set(math.log(self.op1))

    def pct(self):
        self.op1 = float(self.n.get())
        self.n.set(self.op1 * 100)

    def sqrt(self):
        self.op1 = float(self.n.get())
        self.n.set(math.sqrt(self.op1))

    def pow(self):
        self.opt = 'pow'
        self.op1 = float(self.n.get())
        self.n.set = ('')

    def cal(self):
        Calculator.cal(self)
        if self.opt == 'pow':
            self.n.set(self.op1 ** self.op2)

this is a separate file for the driver of this program to make it run:

import calculator
import math

def main():

    myCal = calculator.BetterCalculator()

    myCal.reorganizeInterface()
    myCal.runInterface()

main()


Without looking at the rest of the code, I see an obvious typo / brain-o in pow:

def pow(self):
    self.opt = 'pow'
    self.op1 = float(self.n.get())
    self.n.set = ('')

That last line should be:

    self.n.set('')

without the = part, so as to call self.n.set, not to replace the function with a string. (Replacing the function with a string will cause a later attempt to call self.n.set to produce the error you saw.)