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!