from collections import namedtuple from functools import partial from itertools import chain import types Context = namedtuple('Context','stack, current, op') def default_context(): return Context([],0.0,None) def add(x,y): return x + y def sub(x,y): return x - y def mult(x,y): return x * y def div(x,y): return x/ y def reverse_sign(x): return -1 * x def pow(x,y): return x ** y square = partial(pow,y=2) unary_functions = {'!' : reverse_sign, '@' : square } def handle_unary_op(ctx,x): return ctx._replace(current = unary_functions[x](ctx.current), op = None) binary_functions = {'+' : add, '-' : sub, '*' : mult, '/' : div} def handle_binary_op(ctx,x): return ctx._replace(op = binary_functions[x]) def handle_float(ctx,x): if not ctx.op : return ctx._replace(current = float(x)) else : return ctx._replace(current = ctx.op(ctx.current,float(x)), op = None) def start_brace(ctx): newstack = ctx.stack newstack.append((ctx.current,ctx.op)) return ctx._replace( stack = newstack, current = 0.0, op = None) def end_brace(ctx): stack = ctx.stack current = ctx.current oldcurrent, oldop = stack.pop() oldctx = Context(stack,oldcurrent,oldop) return process_key(oldctx,current) tokens = { '(': start_brace, ')' : end_brace} def handle_tokens(ctx,x): return tokens[x](ctx) function_groups = { tuple(unary_functions.keys()) : handle_unary_op, tuple(binary_functions.keys()) : handle_binary_op, tuple(tokens.keys()) : handle_tokens } def process_key(ctx,key): if isinstance(key,(types.FloatType,types.IntType, types.LongType)) : return handle_float(ctx,key) elif isinstance(key,(types.StringType)) : for function_class in function_groups : if key in function_class : return function_groups[function_class](ctx,key) return ctx def process_keys(keys): # ctx = default_context() # for key in keys : # ctx = process_key(ctx,key) # return ctx return reduce(lambda ctx,key : process_key(ctx,key), keys, default_context()) def plus(n): count = 1 while count <= n : yield '+', count count += 1 if __name__ == "__main__" : assert process_keys((2,'+', 3)).current == 5 assert process_keys((2, '!', '+', 5)).current == 3 assert process_keys((2, '@')).current == 4 assert process_keys((2,'+',3,'*',5)).current == 25 assert process_keys((2,'+','(',3,'*',5,')')).current == 17 keys = list(chain.from_iterable(plus(10)))[1:] assert process_keys(keys) == 55