Reputation: 35
I would like to know if there is a way to print each step considering python follows PEMDAS 1. Can I make it print each step it does in solving this problem without building my own library?
print_steps('(3+7-2)*4/(3+32)')
1 Parentheses, Exponents, Multiplication and Division, and Addition and Subtraction
Upvotes: 0
Views: 284
Reputation: 20930
You could use ast.parse
and ast.dump
to get a grasp of it.
import ast
ast.dump(ast.parse('(3+7-2)*4/(3+32)', mode='eval'))
If formatted nicely, the output can look like this:
Expression(
body=BinOp(
left=BinOp(
left=BinOp(
left=BinOp(
left=Num(n=3),
op=Add(),
right=Num(n=7)
),
op=Sub(),
right=Num(n=2)
),
op=Mult(),
right=Num(n=4)
),
op=Div(),
right=BinOp(
left=Num(n=3),
op=Add(),
right=Num(n=32)
)
)
)
Inspired by jez's answer I came up with the following solution to transform the dump into some linear steps:
import operator
Expression = lambda body: body
Num = lambda n: n
USub = lambda : ('-', operator.neg)
Add = lambda : ('+', operator.add)
Sub = lambda : ('-', operator.sub)
Mult = lambda : ('*', operator.mul)
Div = lambda : ('/', operator.truediv)
FloorDiv = lambda : ('//', operator.floordiv)
def UnaryOp(op, operand):
print(op[0], operand)
result = op[1](operand)
print(' =', result)
return result
def BinOp(left, op, right):
result = op[1](left, right)
print(left, op[0], right, '=', result)
return result
eval(ast.dump(ast.parse('(3+7-2)*4/(3+32)', mode='eval')))
It prints:
3 + 7 = 10
10 - 2 = 8
8 * 4 = 32
3 + 32 = 35
32 / 35 = 0.9142857142857143
astviewer can give you a graphical represention of the tree. For example astviewer.main.view(source_code='(3+7-2)*4/(3+32)', mode='eval')
gives you:
Upvotes: 2
Reputation: 15369
The "library" can be pretty lightweight:
class verbose_number:
def __init__(self, value): self.value = value
def operate(self, operator, other):
other = getattr(other, 'value', other)
result = eval('self.value %s other' % operator)
print('%r %s %r = %r' % (self.value, operator, other, result))
return self.__class__(result)
def __add__(self, other): return self.operate('+', other)
def __sub__(self, other): return self.operate('-', other)
def __mul__(self, other): return self.operate('*', other)
def __div__(self, other): return self.operate('/', other)
def __floordiv__(self, other): return self.operate('//', other)
def __truediv__(self, other): return self.operate('/', other)
def __pow__(self, other): return self.operate('**', other)
def __mod__(self, other): return self.operate('%', other)
def __neg__(self): return self.__class__(-self.value)
def __pos__(self): return self.__class__(+self.value)
def __repr__(self): return repr(self.value)
def __int__(self): return int(self.value)
def __float__(self): return float(self.value)
Now any arithmetic computation that involves a verbose_number
instance gets printed and returns another verbose_number
, so the calculation is printed step by step:
>>> from __future__ import division
>>> (verbose_number(3)+7-2)*4/(3+32)
3 + 7 = 10
10 - 2 = 8
8 * 4 = 32
3 + 32 = 35
32 / 35 = 0.9142857142857143
Note that this relied on the fact that I made the first number in the expression a verbose_number
. A refinement on the approach is to write a handy routine for parsing string expressions:
import re
def print_steps(expression):
return eval(re.sub(r'([0-9\.]+([eE]-?[0-9]+)?)', r'verbose_number(\1)', expression))
This works by turning every numeric literal in the string into a verbose_number
constructor call, thereby ensuring that all steps will be verbose no matter where Python's parser starts in the expression. Here's how it can be used to evaluate your example:
>>> print_steps('(3+7-2)*4/(3+32)')
3 + 7 = 10
10 - 2 = 8
8 * 4 = 32
3 + 32 = 35
32 / 35 = 0.9142857142857143
Upvotes: 2
Reputation: 76254
Nope. Not even dis.dis
will show you individual steps since it all gets simplified out to a single constant before being compiled to bytecode.
>>> def f():
... return (3+7-2)*4/(3+32)
...
>>> import dis
>>> dis.dis(f)
2 0 LOAD_CONST 10 (0.9142857142857143)
3 RETURN_VALUE
Upvotes: 1