|
Most of the code by volume in this post's final product (and most of the ugliness you're probably seeing in it) comes from dealing separately with the arity of different operations (`compute_operation_with_one_operand`, `compute_operation_with_two_operands`, etc) -- which retains a whole lot of copy-paste-but-change-one-small-thing-in-the-middle boilerplate. 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: