forked from eclarson/PythonIntroBridge
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalculators.py
144 lines (107 loc) · 4.64 KB
/
calculators.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from __future__ import print_function
class CalculatorError(ValueError):
'''raise this when the user causes a mistake from the calculator'''
class Calculator:
def __init__(self):
import operator as oper
# add dictionary of operations and function passing
self.operations_list = {'+':oper.add,
'-':oper.sub,
'*':oper.mul,
'/':oper.truediv,
'^':oper.pow,
'%':oper.mod,
}
self.eval_queue = []
#==Queue Operations========
def clear_queue(self):
self.eval_queue = []
def print_queue(self):
print("Current Stack:", self.eval_queue)
def addto_queue(self,value):
tmp = self.convert_user_input(value)
self.eval_queue.append( tmp )
# evaluate operation if it was entered
if self.isoperation(self.eval_queue[-1]):
result = self.eval_queue.pop()
if len(self.eval_queue)<2:
# not enough elements to perform an operation
raise CalculatorError('Not enough values to perform operation')
v2 = self.eval_queue.pop()
v1 = self.eval_queue.pop()
result = calc.perform_operation(result,(v1,v2))
self.eval_queue.append(result)
def print_operations(self):
# print supported operations
print('Operations List:', end=' ')
[print(x, end=', ') for x in self.operations_list.keys()]
print('')
#==check type Operations========
def isoperation(self, value):
if value in self.operations_list.keys():
return True
else:
return False
def isfloat(self, value):
try:
tmp = float(value)
return True
except ValueError:
return False
#===evalaute operations============
def convert_user_input(self, value):
if self.isfloat(value):
return float(value)
elif self.isoperation(value) :
return value # leave as is and interpret operation later
else:
raise CalculatorError('Invalid entry. Entry must be number or supported operator.')
def perform_operation(self, op,vals):
if self.isoperation(op):
return self.operations_list[op](vals[0],vals[1])
return op
class Operator:
def __init__(self, func, num_args=2):
self.func = func
self.num_args = num_args
class CustomCalculator(Calculator):
def __init__(self):
# THIS OVERWRITES THE INIT FUNCTION OF INHERITED CLASS
import operator as oper
# add dictionary of operations and function passing, include basic operations here
self.operations_list = {'+':Operator(oper.add),
'-':Operator(oper.sub),
'*':Operator(oper.mul),
'/':Operator(oper.truediv),
'^':Operator(oper.pow),
'%':Operator(oper.mod),
'abs':Operator(oper.abs,num_args=1),
}
self.eval_queue = []
def add_custom_operations(self,filename):
import json
with open(filename) as file:
data = json.loads(file.read()) # Grab file data
import math
for key,module in data.items():
if hasattr(math, module):
self.operations_list[key] = Operator(getattr(math, module), num_args = 1)
def addto_queue(self,value):
tmp = self.convert_user_input(value)
self.eval_queue.append( tmp )
# evaluate operation if it was entered
if self.isoperation(self.eval_queue[-1]):
result = self.eval_queue.pop()
num_args = self.operations_list[result].num_args
if len(self.eval_queue)<num_args:
# not enough elements to perform an operation
raise CalculatorError('Not enough values to perform operation')
args = []
for i in range(num_args):
args.append(self.eval_queue.pop())
result = self.perform_operation(result,args)
self.eval_queue.append(result)
def perform_operation(self, op, vals):
if self.isoperation(op):
return self.operations_list[op].func(*vals) # pass list as arguments
return op