No!!!!!!!!
The original code looks by far the best to me. Why over-complicate?
No!!!!!!!!
The original code looks by far the best to me. Why over-complicate?
That can be taken further and generalized out.
It's been a while since I did much Python metaprogramming-navel-gazing, but if you can't do something to automatically detect the arity of the operations' lambdas/functions, you can at least explicitly annotate the operations data with their arity -- which is already implicitly being done (as code instead of data) in `compute`'s 3 if-statements + the 3 "compute_with_N_operands" functions.
From there, you'll only have 1 case once, instead of 3 cases with each one manifesting in 2 different places. And just about half of the code disappears.
----
edit: since adjkant already covered the "automatically detect the arity of the operations' lambdas/functions" approach to removing all the cases, (https://news.ycombinator.com/item?id=17329772), here is the gist of what I meant by "explicitly annotate the operations data with their arity":
import math, operator
class rpn_engine:
def __init__(self):
self.stack = []
self.catalog = {"+": (2, operator.add),
"-": (2, operator.sub),
"*": (2, operator.mul),
"/": (2, operator.truediv),
"^2": (1, lambda x: x * x),
"SQRT": (1, math.sqrt),
"C": (0, self.stack.pop),
"AC": (0, self.stack.clear)}
def compute(self, operation):
(arity, op) = self.catalog[operation]
operands = reversed([self.stack.pop() for _ in range(arity)])
return self.stack.push(op(*operands))Instead of each operation taking a variable number of numbers and then either returning a value or directly changing the state of the stack (which was also a bug in my previous gist, in pushing the result of C and AC): homogenize the types of the operations by making all of them take a stack and return a stack.
You could also wrap all of the basic arithmetic functions with a higher-level function so that, eg, `add` would still not actually have to be aware of the stack:
import math, operator
def stackFunction(arity, function):
return lambda stack: stack[:-arity] + [function(*stack[-arity:])]
class rpn_engine:
def __init__(self):
self.stack = []
self.catalog = {"+": stackFunction(2, operator.add),
"-": stackFunction(2, operator.sub),
"*": stackFunction(2, operator.mul),
"/": stackFunction(2, operator.truediv),
"^2": stackFunction(1, lambda x: x * x),
"SQRT": stackFunction(1, math.sqrt),
"C": lambda stack: stack[:-1],
"AC": lambda stack: []}
def compute(self, operation):
self.stack = self.catalog[operation](self.stack)
def push(self, number):
self.stack.append(number)“!”: lambda x: math.factorial(x),
However, it’s probably a matter of taste... but I do like the last code more. :)
"!": math.factorial,
The lambda wrapper isn't doing anything here.