I’m making a calculator in python and I’ve run into a little problem when processing parentheses. Here’s the code:
def split_par(lst):
lst_two = lst.copy()
for i in lst_two:
if i == '(':
index = lst_two.index(i)
del lst_two[0:index + 1]
elif i == ')':
close_index = lst_two.index(i)
del lst_two[close_index:]
del lst[index:close_index + 1]
str = pemdas_op(lst_two)
lst.insert(index, str)
if '(' in lst:
split_par(lst)
return lst
If I run this code with an input of, for example, ['(', 12, '+', 7, ')', '*', '(', 12, '+', 7, ')'], it’ll give me the following error: UnboundLocalError: local variable 'index' referenced before assignment
What I find fascinating is if I change del lst[index:close_index + 1] to del lst[index:close_index + 2] It wont give me an error. It will give me the following output: [19, '*', 19, 7, ')'] Which is obviously not what I need. Also I will detail that the line str = pemdas_op(lst_two) is calling a separate function in my program that runs the list through a stack and consolidates the equations based on the order of operations. I don’t think it’s necessary to see that one but if it is let me know. Anyways, how can I solve this problem?
I don’t think I ever thought of it because (as far as I’m concerned at least) there’s not an instance where you’ll put a closing parentheses before an opening one in a mathematical expression, so I just ignored that as a potential issue. However you are right. With further inspection I see that the issue does lie in the elif section of the function. So I changed the code to this to solve the issue:
def split_par(lst):
if '(' in lst:
lst_two = lst.copy()
for i in lst_two:
if i == '(':
index = lst_two.index(i)
index_one = lst.index(i)
del lst_two[0:index + 1]
elif i == ')':
close_index = lst_two.index(i)
index_two = lst.index(i)
del lst_two[close_index:]
del lst[index_one:index_two + 1]
str = pemdas_op(lst_two)
lst.insert(index_one, str)
print(lst)
split_par(lst)
else:
return lst
Unfortunately this code also has a problem, as goes with programing, that (I hope) you can help with. As the code stands, if I input ['(', 12, '+', 7, ')', '*', '(', 12, '+', 7, ')'], it will return none. I honestly don’t know what the issue is because the little print(lst) block at the bottom will print [19, '*', 19] which should then be recursed through the function, where it will fail the initial if statement and go to the else statement where it should return [19, '*', 19], but it doesn’t. It returns None. Clearly I’ve done something wrong in my understanding of what’s going on, and I don’t know what I’ve missed.
The return returns to the most recent caller. Your code is doing something like this (I didn’t follow the logic exactly, but it’s close)…
split_par(<first sequence>)
... # does some stuff
split_par([19, '*', 19])
...
return [19, '*', 19]
... #ignores the return value from split_par()
returns None
It is possible you want to change the recursive call to
return split_par(lst)
But since you haven’t included pemdas_op, I can’t run the program.
def pemdas_op(lst):
lst_index = 0
pemdas_stack = ['^', '*', '/', '+', '-']
while pemdas_stack and len(lst) > 1:
popped = pemdas_stack.pop(lst_index)
if popped in lst:
index = lst.index(popped)
if lst[index] == '^':
first = index - 1
second = index + 1
amount = lst[first] ** lst[second]
del lst[first:second+1]
lst.insert(first, amount)
elif lst[index] == '*':
first = index - 1
second = index + 1
amount = lst[first] * lst[second]
del lst[first:second + 1]
lst.insert(first, amount)
elif lst[index] == '/':
first = index - 1
second = index + 1
amount = lst[first] / lst[second]
del lst[first:second + 1]
lst.insert(first, amount)
elif lst[index] == '+':
first = index - 1
second = index + 1
amount = lst[first] + lst[second]
del lst[first:second + 1]
lst.insert(first, amount)
elif lst[index] == '-':
first = index - 1
second = index + 1
amount = lst[first] - lst[second]
del lst[first:second + 1]
lst.insert(first, amount)
else:
continue
str = 0
if len(lst) == 1:
for i in lst:
str += i
return str
Although I did change that one line to return split_par(lst) and it worked almost seamlessly, so, thank you.