Я делаю калькулятор с использованием Python, и он показывает ошибку при вычислении выражений с круглыми скобками - PullRequest
0 голосов
/ 01 мая 2018

Эта ошибка отображается при расчете выражений с круглыми скобками, например-> 86 * 4 (3 + 5) 88:

TypeError: объект 'int' не может быть вызван

когда я не пользуюсь кнопками калькулятора и набираю с помощью кнопок на клавиатуре, ошибка не отображается, но при нажатии на кнопку даётся неправильный ответ.

Пожалуйста, проверьте мой код и укажите ошибку.

from tkinter import *

cal = Tk()
cal.title("Smart Calculator")

txtDisplay = Entry(cal, font=('arial', 20, 'bold'), bd=30, insertwidth=4, 
bg="powder blue", justify='right')

class Calculator:

    def __init__(self):
        self.result = 0
        self.current = 0
        self.operator = ""

    def btnClick(self, num):
            self.operator = self.operator + str(num)
            txtDisplay.delete(0, END)
            txtDisplay.insert(0, self.operator)
            self.expOutput(self.operator)

    def expOutput(self, operator):
        try:
            self.result = str(eval(operator))
            txtDisplay.delete(0, END)
            txtDisplay.insert(0, string=self.operator + "=" + self.result)
            self.current = 0
        except SyntaxError:
            txtDisplay.delete(0, END)
            txtDisplay.insert(0, self.operator)

    def oprtrClick(self, op):
        if self.current is 0:
            self.current = 1
            self.operator = self.operator + op
            txtDisplay.delete(0, END)
            txtDisplay.insert(0, string=self.operator)
        else:
            self.operator = self.operator + op
            self.expOutput(self.operator)

    def equals(self):
        self.operator = self.result
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, string=self.operator)

    def clear(self):
        self.__init__()
        txtDisplay.delete(0, END)

    def delete(self):
        self.operator = self.operator[: -1]
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, string=self.operator)

smartCal = Calculator()

btn0 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 
'bold'), text="0",bg="powder blue", command=lambda: smartCal.btnClick(0))


btn1 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 
'bold'), text="1",
          bg="powder blue", command=lambda: smartCal.btnClick(1))

btn2 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 
'bold'), text="2",bg="powder blue", command=lambda: smartCal.btnClick(2))


btn3 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 
'bold'), text="3",
          bg="powder blue", command=lambda: smartCal.btnClick(3))

btn4 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="4",
          bg="powder blue", command=lambda: smartCal.btnClick(4))

btn5 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="5",
          bg="powder blue", command=lambda: smartCal.btnClick(5))

btn6 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="6",
          bg="powder blue", command=lambda: smartCal.btnClick(6))

btn7 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="7",
          bg="powder blue", command=lambda: smartCal.btnClick(7))

btn8 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="8",
          bg="powder blue", command=lambda: smartCal.btnClick(8))

btn9 = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="9",
          bg="powder blue", command=lambda: smartCal.btnClick(9))

btnDecimal = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text=".",
               bg="powder blue", command=lambda: smartCal.btnClick("."))

btnLeftParen = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="(",
               bg="powder blue", command=lambda: smartCal.btnClick("("))

btnRightParen = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text=")",
               bg="powder blue", command=lambda: smartCal.btnClick(")"))

Add_btn = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="+",
             bg="powder blue", command=lambda: smartCal.oprtrClick("+"))

Sub_btn = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="-",
             bg="powder blue", command=lambda: smartCal.oprtrClick("-"))

Mul_btn = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="*",
             bg="powder blue", command=lambda: smartCal.oprtrClick("*"))

Div_btn = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="/",
             bg="powder blue", command=lambda: smartCal.oprtrClick("/"))

btnEquals = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="=",
               bg="powder blue", command=smartCal.equals)

btnClear = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="C",
              bg="powder blue", command=smartCal.clear)

btnBackspace = Button(cal, padx=16, pady=16, bd=8, fg="black", font=('arial', 20, 'bold'), text="⌫",
              bg="powder blue", command=smartCal.delete)

# ~*~*~Positioning~*~*~

txtDisplay.grid(columnspan=4)
# =========ROW1================== #
btn7.grid(row=1, column=0)
btn8.grid(row=1, column=1)
btn9.grid(row=1, column=2)
Add_btn.grid(row=1, column=3)
# =========ROW2================== #
btn4.grid(row=2, column=0)
btn5.grid(row=2, column=1)
btn6.grid(row=2, column=2)
Sub_btn.grid(row=2, column=3)
# =========ROW3================== #
btn1.grid(row=3, column=0)
btn2.grid(row=3, column=1)
btn3.grid(row=3, column=2)
Mul_btn.grid(row=3, column=3)
# =========ROW4================== #
btn0.grid(row=4, column=0)
btnClear.grid(row=4, column=1)
btnEquals.grid(row=4, column=2)
Div_btn.grid(row=4, column=3)
# =========ROW5================== #
btnDecimal.grid(row=5, column=0)
btnLeftParen.grid(row=5, column=1)
btnRightParen.grid(row=5, column=2)
btnBackspace.grid(row=5, column=3)

cal.mainloop()

Ответы [ 2 ]

0 голосов
/ 02 мая 2018

Я решил проблему без использования функции синтаксического анализа. Я использовал две новые переменные - isButton и isRightParen и две новые функции - leftParenthesesClick () и rightParenthesesClick (). isButton отслеживает, была ли последняя нажатая кнопка цифрой (0-9). когда пользователь нажимает левые круглые скобки, сначала он проверяет, равно ли isRightParen значение 1, затем он включает знак * перед левыми круглыми скобками, затем, если isButton равен 1, тогда также * включается, в противном случае левые круглые скобки выводятся как есть.

Пожалуйста, проверьте мой код и скажите, в порядке ли это, есть ли какая-то ошибка или есть лучший и более короткий способ сделать это. @Jacques Gaudin @PM 2Ring Позже я попробую это с функцией синтаксического анализа, а также предложил. :)

def __init__(self):
    self.var1 = ""
    self.var2 = ""
    self.output = 0
    self.current = 0
    self.operator = ""
    self.isButton = 0
    self.isRightParen = 0

def btnClick(self, num):
    if self.isRightParen is 1:
        self.operator = self.operator + "*" + str(num)
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, self.operator)
        self.expOutput(self.operator)
        self.isButton = 1
        self.isRightParen = 0

    elif self.isRightParen is 0:
        self.operator = self.operator + str(num)
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, self.operator)
        self.expOutput(self.operator)
        self.isButton = 1
        self.isRightParen = 0

def leftParenthesesClick(self):

    if self.isRightParen is 1:
        self.operator = self.operator + "*" + "("
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, self.operator)
        self.isRightParen = 0

    elif self.isButton is 0:
        self.operator = self.operator + "("
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, self.operator)
        self.isRightParen = 0
    elif self.isButton is 1:
        self.operator = self.operator + "*" + "("
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, self.operator)
        self.isRightParen = 0

def rightParenthesesClick(self):
    self.operator = self.operator + ")"
    txtDisplay.delete(0, END)
    txtDisplay.insert(0, self.operator)
    self.expOutput(self.operator)
    self.isRightParen = 1

def expOutput(self, operator):
    try:
        self.output = str(eval(operator))
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, string=self.operator + "=" + self.output)
        self.current = 0
    except SyntaxError:
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, self.operator)


def oprtrClick(self, op):
    if self.current is 0:
        self.current = 1
        self.operator = self.operator + op
        txtDisplay.delete(0, END)
        txtDisplay.insert(0, string=self.operator)
        self.isButton = 0
        self.isRightParen = 0
    else:
        self.operator = self.operator + op
        self.isButton = 0
        self.isRightParen = 0
        self.expOutput(self.operator)
0 голосов
/ 01 мая 2018

В вашем методе expOutput вы должны добавить пропущенный знак * в строку operator до и после открывающих или закрывающих скобок.

Это необходимо сделать перед вызовом eval(operator), вызвав функцию синтаксического анализа, скажем, add_missing_mult.

Наивная реализация функции синтаксического анализа может выглядеть следующим образом:

def add_missing_mult(s):

    splitted = s.split('(')
    for i, sub in enumerate(splitted[:-1]):
        if sub[-1].isdigit() or sub[-1] == '.':
            splitted[i] += "*"
    s = '('.join(splitted)

    splitted = s.split(')')
    for i, sub in enumerate(splitted[1:]):
        if sub[0].isdigit():
            splitted[i+1] = "*" + splitted[i+1]
    return ')'.join(splitted)

add_missing_mult('86*4(3+5)88')

>>>'86*4*(3+5)*88'

, а затем в expOutput:

operator = add_missing_mult(operator)
try:
    self.result = str(eval(operator))
    txtDisplay.delete(0, END)
    ...

Но в реальном проекте вы бы хотели использовать регулярное выражение, как в этот вопрос

...