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

Он показывает эту ошибку при вычислении выражений со скобками типа-> 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()

Я не смотрел внимательно на ваш код. Но поскольку вы используете eval, вам нужно писать выражения, используя правильный синтаксис Python. 86*4(3+5)88 - это синтаксическая ошибка, вам нужен 86*4*(3+5)*88. Обратите внимание, что при использовании eval возникают проблемы с безопасностью. Есть способы сделать это лучше.

PM 2Ring 01.05.2018 13:27

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

preetika mondal 01.05.2018 13:31

Если это домашнее задание, то, возможно, ваш учитель ожидает, что вы будете использовать eval. Сделать это правильно немного сложнее, так как вам нужно написать код, который может анализировать арифметические выражения, или использовать стороннюю библиотеку, такую ​​как пипарсинг, чтобы выполнить синтаксический анализ за вас.

PM 2Ring 01.05.2018 13:46
eval не взорвет ваш компьютер. :) Но это означает, что кто-то, использующий вашу программу калькулятора, может вычислять произвольные выражения, а это значит, что он может запускать любой код Python и выполнять любую команду в системе, включая форматирование жесткого диска. Если они запускают калькулятор на своем компьютере, это не проблема, поскольку они все равно могут делать такие вещи.
PM 2Ring 01.05.2018 13:50

Сообщение об ошибке говорит гораздо больше. Пожалуйста, включите его полностью.

Jongware 01.05.2018 14:28

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

Bryan Oakley 01.05.2018 15:22
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
6
480
2

Ответы 2

В вашем методе 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)
    ...

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

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

Пожалуйста, проверьте мой код и скажите, подходит ли этот способ, есть ли ошибка или есть лучший и более короткий способ сделать это. @ Жак Годен @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)

Другие вопросы по теме