Skip to content

Instantly share code, notes, and snippets.

@AndreyeuIvan
Last active December 21, 2019 10:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndreyeuIvan/1c8e1aec053a6d609f6939ba6167a732 to your computer and use it in GitHub Desktop.
Save AndreyeuIvan/1c8e1aec053a6d609f6939ba6167a732 to your computer and use it in GitHub Desktop.
Calculator
import re
from operations import Operation
class UnknownOperation(NotImplementedError): pass
class UnknownError(Exception): pass
class Calculator(object):
REGEXP_ALL = r"((\d{1,20}(\.|\,)\d{1,20})|(\d{1,20})|(\+|\-|\*|\^|\#|\/|\(|\)|\.))"
def __init__(self, *args, **kwargs):
self.OPERATIONS = Operation.get_operations()
self.start()
def get_data(self):
"""
This function for getting data from user
return: list of elements
"""
input_str = input("Введите операцию: ")
matches = re.finditer(self.REGEXP_ALL, input_str, re.MULTILINE)
return [match.group() for match in matches]
def check_data(self, elements): # проверяет исключения, все, чтобы не было ошибок
if elements[0] in self.OPERATIONS or elements[-1] in self.OPERATIONS: # проверяем
raise UnknownError
for element in elements:
if isinstance(element, str) and element not in self.OPERATIONS:
raise UnknownOperation(element)
def compress(self, elements, index):
first = elements[index-1]
second = elements[index+1]
cls = self.OPERATIONS.get(elements[index], None)
operation = cls()
left_finish = 0 if index == 1 else index - 1
right_first = len(elements) if index == len(elements) - 2 else index + 2
return elements[:left_finish] + [operation.calculate(first, second)] + elements[right_first:]
def get_priority(self, elements):
result = []
for index, element in enumerate(elements):
if not isinstance(element, (int, float)):
result += [(index, self.OPERATIONS.get(element).priority)]
import pdb; pdb.set_trace()
return sorted(result, key=lambda k: k[1])
def calc(self, elements):
for index, element in enumerate(elements):
try:
element = float(element.replace(',', '.'))
except ValueError:
pass
elements[index] = element
self.check_data(elements)
print(elements)
while elements.count(")") > 0:
end = elements.index(")")
start = (end - 1) - list(reversed(elements[:end])).index("(")
cutted = elements[start + 1:end]
while len(cutted) > 1:
priority = self.get_priority(cutted)
cutted = self.compress(cutted, priority[0][0])
elements[start:end + 1] = cutted
print(elements)
while len(elements) > 1:
priority = self.get_priority(elements)
print(priority)
elements = self.compress(elements, priority[0][0])
print(elements)
return elements[0]
def start(self):
print("Для выхода нажмите <Ctrl> - C")
while True:
try:
elements = self.get_data()
except KeyboardInterrupt:
print("Завершение программы")
break
try:
result = self.calc(elements)
print(result)
except ZeroDivisionError:
print("На ноль делить нельзя!")
except UnknownOperation as err:
print('UnknownOperation', err) # определяем какая неизвестная операция
except UnknownError:
print('UnknownError!')
from calc import Calculator, UnknownOperation, UnknownError
INPUT_FILENAME = "input.txt"
OUTPUT_FILENAME = "output.txt"
def get_data():
with open(INPUT_FILENAME) as file:
data = file.readlines()
data = [x.strip() for x in data]
return data
def write_data(output_data):
output_data = [str(x)+"\n" for x in output_data]
print(output_data)
with open(OUTPUT_FILENAME, "w") as out_file:
out_file.writelines(output_data)
if __name__ == "__main__":
calc = Calculator(start_auto=False)
data = get_data()
results = []
for line in data:
elements = calc.prepare_data(line)
try:
result = calc.calc(elements)
results.append(result)
except ZeroDivisionError:
results.append("На ноль делить нельзя!")
except UnknownOperation as err:
results.append('UnknownOperation') # определяем какая неизвестная операция
except UnknownError:
results.append('UnknownError!')
write_data(results)
print(results)
from tkinter import Tk, Frame, Label, Button
from calc import Calculator, UnknownOperation, UnknownError
class Main(Frame):
formula = "0"
def __init__(self, root):
super().__init__(root)
self.build()
def build(self):
self.calc = Calculator(start_auto=False)
self.lbl_err = Label(
text="",
font=("Times New Roman", 21, "bold"),
bg="#000", foreground="#FF0"
)
self.lbl_err.place(x=11, y=5)
self.lbl = Label(
text=self.formula,
font=("Times New Roman", 21, "bold"),
bg="#000", foreground="#FFF"
)
self.lbl.place(x=11, y=50)
btns = [
"C", "DEL", "*", "=",
"1", "2", "3", "/",
"4", "5", "6", "+",
"7", "8", "9", "-",
"(", "0", ")", "X^2",
]
x = 10
y = 100
for btn in btns:
command = lambda x=btn: self.command(x)
Button(
text=btn, bg="#FFF",
font=("Times New Roman", 15), command=command
).place(
x=x, y=y, width=115, height=79
)
x += 117
if x > 400:
x = 10
y += 81
def get_result(self, string):
result = "0"
error = ""
elements = self.calc.prepare_data(string)
try:
result = self.calc.calc(elements)
except ZeroDivisionError:
error = "На ноль делить нельзя!"
except UnknownOperation as err:
error = 'UnknownOperation'
except UnknownError:
error = 'UnknownError!'
return str(result), str(error)
def command(self, symbol):
need_update = True
if symbol == "C":
self.formula = "0"
elif symbol == "DEL":
self.formula = self.formula[0:-1]
elif symbol == "=":
result, error = self.get_result(self.formula)
if error:
self.lbl_err.configure(text=error)
need_update = False
else:
self.formula = result
elif symbol == "X^2":
error = ""
try:
float(self.formula)
except ValueError:
result1, error = self.get_result(self.formula)
try:
if error:
raise ValueError(error)
result, error = self.get_result(result1 + '^2')
if error:
raise ValueError(error)
self.formula = result
except ValueError as error:
self.lbl_err.configure(text=str(error))
need_update = False
else:
if self.formula == "0":
self.formula = ""
self.formula += symbol
if need_update:
self.update()
def update(self):
if self.formula == "":
self.formula = "0"
self.lbl.configure(text=self.formula)
self.lbl_err.configure(text="")
if __name__ == "__main__":
root = Tk()
root["bg"] = "#000"
root.title("Калькулятор")
root.geometry("485x550+200+200")
root.resizable(False, False)
app = Main(root)
app.pack()
root.mainloop()
from calc import Calculator
calc = Calculator(start_auto=False)
calc.start()
SUM = "+"
DEC = "-"
MUL = "*"
DIV = "/"
EXP = "^"
ROT = "#"
BR1 = "("
BR2 = ")"
END = "."
class Operation(object):
__priority = 0
__identificator = None
def calculate(self, *args, **kwargs):
raise NotImplementedError
@classmethod
def get_operations(cls):
return {
SUM: SumOperation,
DEC: DecOperation,
MUL: MultiplicationOperation,
DIV: DivisionOperation,
EXP: ExponentialOperation,
ROT: RootOfOperation,
BR1: BracketOperation,
BR2: BracketOperation,
}
@classmethod
def priority(cls):
return cls.__priority
class SumOperation(Operation):
__priority = 3
__identificator = [SUM]
def calculate(self, *args, **kwargs):
return sum(args)
class DecOperation(Operation):
__priority = 3
__identificator = [DEC]
def calculate(self, *args, **kwargs):
result = args[0]
for arg in args[1:]:
result -= arg
return result
class MultiplicationOperation(Operation):
__priority = 2
__identificator = [MUL]
def calculate(self, *args, **kwargs):
result = args[0]
for arg in args[1:]:
result *= arg
return result
class DivisionOperation(Operation):
__priority = 2
__identificator = [DIV]
def calculate(self, *args, **kwargs):
result = args[0]
for arg in args[1:]:
result /= arg
return result
class ExponentialOperation(Operation):
__priority = 1
__identificator = [EXP]
def calculate(self, a, n):
return a ** n
class RootOfOperation(Operation):
__priority = 1
__identificator = [ROT]
def calculate(self, a, n):
return a ** (1 / n)
class BracketOperation(Operation):
__priority = 1
__identificator = [BR1, BR2]
def calculate(self, *args, **kwargs):
return
if __name__ == "__main__":
import traceback
TEST_CASES = [
{"cls": SumOperation, "args": [1, 2, 3], "expected_result": 6},
{"cls": SumOperation, "args": [2, 3], "expected_result": 5},
{"cls": DecOperation, "args": [1, 2, 3], "expected_result": -4},
{"cls": MultiplicationOperation, "args": [8, 8, 2, 2], "expected_result": 256},
{"cls": DivisionOperation, "args": [16, 4, 2, 1], "expected_result": 2},
{"cls": ExponentialOperation, "args": [8, 2], "expected_result": 64},
{"cls": RootOfOperation, "args": [16, 2], "expected_result": 4},
{"cls": BracketOperation, "args": [16, 2], "expected_result": None},
]
green = 0
red = 0
for test_case in TEST_CASES:
cls = test_case["cls"]
op = cls()
expected_result = test_case["expected_result"]
result = op.calculate(*test_case["args"])
try:
assert result == expected_result, f"calculate returns: {result}, expected: {expected_result}, operation is {cls.__name__}"
green += 1
except AssertionError:
red += 1
print(traceback.format_exc())
all = green + red
print(f"Run {all} tests, {green} passed, {red} failed")
@AndreyeuIvan
Copy link
Author

Тесткейсы
Работа с Файлами
@classmethod
Экземляр класса и класс (чертеж дома и дом)
Пишите свой код

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment