I am trying to make calculator that can solve expressions with basic 4 operators, like 1+2*3-4/5, however it does not work and I do not know what is wrong. Please check my code.
Here is a simple python calculator program, feel free to use it:
#Python calculator
def menu():
print ("Welcome to calculator.py")
print ("your options are:")
print (" ")
print ("1) Addition")
print ("2) Subtraction")
print ("3) Multiplication")
print ("4) Division")
print ("5) Quit calculator.py")
print (" ")
return input ("Choose your option: ")
def add(a,b):
print (a, "+", b, "=", a + b)
def sub(a,b):
print (b, "-", a, "=", b - a)
def mul(a,b):
print (a, "*", b, "=", a * b)
def div(a,b):
print (a, "/", b, "=", a / b)
loop = 1
choice = 0
while loop == 1:
choice = menu()
if choice == 1:
add(input("Add this: "),input("to this: "))
elif choice == 2:
sub(input("Subtract this: "),input("from this: "))
elif choice == 3:
mul(input("Multiply this: "),input("by this: "))
elif choice == 4:
div(input("Divide this: "),input("by this: "))
elif choice == 5:
loop = 0
print ("Thank you for using calculator.py!")
In your code you have no condition on the result of s.partition(c), so even if the partition results in ('anything', '', '') you will do a recursion on the first if.
Edited
Here is simple code in python for creating a calculator same as in Python terminal.
number = input("")
print number
You partition the input string regardless, never checking if the operator is even there. .partition() returns empty strings if the partition character is not present in the input:
>>> '1+1'.partition('*')
('1+1', '', '')
So you'll call s.partition('*') but never check if there is any such operator present, resulting in unconditional calls to ret(). You'll always call ret(parts[0]) * ret(parts[2]) regardless of wether * is present in s or not.
The solution is to either test for the operator first or to check the return value of .partition(). The latter is probably easiest:
for c in ('+','-','*','/'):
parts = s.partition(c)
if parts[1] == '*':
return ret(parts[0]) * ret(parts[2])
elif parts[1] == '/':
return ret(parts[0]) / ret(parts[2])
elif parts[1] == '+':
return ret(parts[0]) + ret(parts[2])
elif parts[1] == '-':
return ret(parts[0]) - ret(parts[2])
Note that I reversed the operator order; yes, multiplication and division need to be applied before addition and subtraction, but you are working in reverse here; splitting up the expression into smaller parts, and the operations are then applied when the sub-expression has been processed.
You could use assignment unpacking to assign the 3 return values of .partition() to easier names:
for c in ('+','-','*','/'):
left, operator, right = s.partition(c)
if operator == '*':
return ret(left) * ret(right)
elif operator == '/':
return ret(left) / ret(right)
elif operator == '+':
return ret(left) + ret(right)
elif operator == '-':
return ret(left) - ret(right)
Next you can simplify all this by using the operator module, which has functions that perform the same operations as your arithmetic operations. A map should do:
import operator
ops = {'*': operator.mul, '/': operator.div, '+': operator.add, '-': operator.sub}
for c in ('+','-','*','/'):
left, operator, right = s.partition(c)
if operator in ops:
return ops[operator](ret(left), ret(right))
The main thing you are doing wrong is that you are checking the value of c rather that the partitioned operator. You can also unpack the result from s.partition to make things a little easier by using left and right for the actual operations.
def ret(s):
s = str(s)
if s.isdigit():
return float(s)
for c in ('-','+','*','/'):
left, op, right = s.partition(c)
if op == '*':
return ret(left) * ret(right)
elif op == '/':
return ret(left) / ret(right)
elif op == '+':
return ret(left) + ret(right)
elif op == '-':
return ret(left) - ret(right)
print(ret('1+2'))
Also, you will need to reverse the order of your operations as you want to first do addition and subtraction, followed by multiplication and division.
What I mean is, if you have an expression like 4+4*3, you want to divide it into
ret(4) + ret(4 * 3)
Since it is a recursive call, you want the operators with the highest precedence to be the last on the call stack so they are executed first when the function returns.
As an example:
print(ret('1+2*6'))
print(ret('3*8+6/2'))
OUTPUT
13.0
27.0
Your dispatching is incorrect. The way you defined your function it will always try to split by '*', which basically calls the ret function recursively with the same arguments...
You'll have to check first whether an "operator" is present in your argument string at all.
Think again!