0
def equalizer(entryblock):
    x = entryblock.get()
    entryblock.delete(0, tk.END)
    entryblock.insert('end', int(x))

so here is a function for my tkinter calculator. I am trying to make a function where it takes the entry box and does the operations and gives the result. For example, if I punch in '1+2+3', I want this function to turn it into 6. Whenever I try this, it gives this error:

ValueError: invalid literal for int() with base 10: '1+2+3' 

Could I use the math module to fix this problem?

Crystallean
  • 125
  • 7
  • A quick way to fix it would be to replace `int(x)` with `eval(x)`. I would advise against executing code that that user may have control over. – Jake Bringham Dec 24 '21 at 00:05
  • There are 2 ways to solve this problem as far as I see it. One is to use `eval` but then you cannot have the user input the values into the entry. Next is to use a AST parser, that way it will be safe from the exploits of `eval`. [Here](https://pastebin.com/MwBBA8ME) is a code for that from [Kevin](https://stackoverflow.com/users/953482/kevin). – Delrius Euphoria Dec 24 '21 at 00:14
  • Similar question: [Safe expression parser in Python](https://stackoverflow.com/questions/3582403/safe-expression-parser-in-python) – Stef Dec 24 '21 at 11:35

1 Answers1

0

There are 3 ways to solve this problem as far as I can think:

  • One is to use eval but then you cannot have the user input the values into the entry, as its not safe.

  • Next is to implement an AST parser suitably, that way you can use user input via Entry and still be safe from the exploits of eval.

  • The third way would be change your logic and make the app work like how the calculator in windows works, this way you do not need eval or anything. You will have to keep reference to the last item given and then add(or any operation) with the next entered item. Video reference: Build A Simple Calculator App - Python Tkinter GUI Tutorial #6, there is a previous part but only follow the logical part of the code, the other part is quite naïve.

For the first approach, this should give you a bare example:

from tkinter import * # Note: Better to use import tkinter as tk and make changes needingly

root = Tk()

def write(num):
    lbl['text'] += num # Add the user inputted number to the end of current text from label

def calc():
    out = eval(lbl['text']) # Get the text and do the operations
    lbl['text'] = str(out) # Change the text with the output

texts = '123456789' # Digits to loop through

lbl = Label(root,font=(0,15),justify='left')
lbl.grid(row=0,column=0,columnspan=3)

# To create a 3x3 grid of widgets, starting from 1 because 0th row/column is already taken by the label
for i in range(1,4):
    for j in range(1,4):
        text = texts[3*(i-1)+(j-1)] # Indexing to get the respective texts
        Button(root,text=text,command=lambda num=text: write(num),width=15).grid(row=i,column=j-1)

# Some buttons outside the normal gridding behavior and with different function
Button(root,text='+',command=lambda: write('+'),width=15).grid(row=i+1,column=0)
Button(root,text='0',command=lambda: write('0'),width=15).grid(row=i+1,column=1)
Button(root,text='=',command=calc,width=15).grid(row=i+1,column=2)
Button(root,text='C',command=lambda: lbl.config(text=''),width=15).grid(row=i+2,columnspan=3,sticky='news')

root.mainloop()

You can design/place the widgets the way you want, notice how the function handles the input and user cant input any number as they wish either.

For the second approach, you can refer here for a code from Kevin that implements ast and does calculation and you can take user input as well and integrate tkinter with that function by making a few tweaks.


So to answer your question:

Could I use the math module to fix this problem?

Nothing I can think of from math does what you are looking for.

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46