Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added final_task/calc/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions final_task/calc/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import argparse
from calc.main_functions import reduction_expression, compare


def main():
try:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лишняя пустая строка

parser = argparse.ArgumentParser(description='Takes mathematical expression')
parser.add_argument('string')
s = parser.parse_args().string
lis = reduction_expression(s)
print(compare(lis))

except Exception:
print('ERROR: Unknown exit')
exit()
114 changes: 114 additions & 0 deletions final_task/calc/main_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import calc.other_functions as o_f

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Человеку, который видит этот код впервые, сложно понять, что значит o_f. Я думаю, в данном случае лучше оставить other_functions

from calc.math_functions import decide_func


def reduction_expression(s):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

лучше избегать названий переменных, которые состоят из одного символа. Такие названия не несут никакой информации.


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

лишняя пустая строка

lis = o_f.finding_elements(s)
lis = o_f.additions(lis)
return lis


def compare(lis):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Из названия функции и названия аргументов нельзя получить информацию, что эта функция делает и что в эту функцию нужно отправить в качестве аргумента. Отсутствие документации усложняет ситуацию. Я бы дал более осмысленное название функции и ее аргументам.

i = 0
while i < len(lis)-1:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

С-style итерирование по коллекции через индексы крайне редко используется в Python. В Python есть замечательный цикл for, который позволяет удобным образом итерироваться по данным в коллекции без использования индексов.

for item in lis:
    # do smt
    pass

Copy link
Author

@Efi-fi Efi-fi Dec 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А если мне не нужно последний элемент проверять, то брать срез?
for item in lis[:-1]:
...

Или чтоб получать индексы использовать range:
for item in range(len(lis)-1):
...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В случае, если нужно взять колекцию без последнего элемента, то можно взять срез.
а если нужно в этом случае еще использовать индексы, то можно использовать функцию enumerate

for index, element in enumerate(lis[:-1]):
    pass

if lis[i] == '==':
a, b = cut(i, lis)
return a == b
elif lis[i] == '<=':
a, b = cut(i, lis)
return a <= b
elif lis[i] == '>=':
a, b = cut(i, lis)
return a >= b
elif lis[i] == '!=':
a, b = cut(i, lis)
return a != b
elif lis[i] == '>':
a, b = cut(i, lis)
return a > b
elif lis[i] == '<':
a, b = cut(i, lis)
return a < b

i += 1

return decide_expression(lis)


def cut(i, lis):
a = decide_expression(lis[:i])
b = decide_expression(lis[i+1:])
return a, b


def decide_expression(s):
s.insert(0, '(')
s.append(')')
st_nums = []
st_ops = []
i = 0

while i < len(s):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Цикл for

verify(s, i, st_nums, st_ops)
i += 1

if len(st_nums) > 1 or len(st_ops):
print('ERROR: not necessary operation')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я думаю, в данном случае будет уместо использовать исключения.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можете дать подсказку как это должно выглядеть, потому что я не совсем понял суть использования исключений.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В данном случае вместо print и выхода из программы можно "бросить" исключение, например:

class InvalidExpressionError(Exception):
    pass

if len(st_nums) > 1 or len(st_ops):
    raise InvalidExpressionError

А на самом верхнем уровне, где вызывается функция main, можно эти исключения обрабатывать и корректно завершать программу:

try:
    main()
except Excpetion as e:
    print(f"ERROR: {e})

В таком случае у нас будет только одна точка, где мы завершаем исполнение этой программы, вместо большого количества функций exit.

PS: код приведен для примера, написан "на коленке" и без проверки того, что он работает.

exit()

return st_nums[0]


def verify(s, i, st_nums, st_ops):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Очень сложно читать код, где названия переменных не несут в себе смысла. Как минимум я бы переименовал переменные s и i


if type(s[i]) == float:
st_nums.append(s[i])

elif s[i] == '(':
st_ops.append('(')
if o_f.prior(s[i+1]) == 1:
st_nums.append(0)

elif s[i] == ')':
if st_ops[-1] == '(':
del st_ops[-1]
else:
try:
st_nums[-2] = o_f.bin_operate(st_nums[-2], st_nums[-1], st_ops[-1])
except Exception:
print('ERROR: not necessary element')
exit()
del st_ops[-1]
del st_nums[-1]
verify(s, i, st_nums, st_ops)

elif o_f.prior(s[i]) == 5:
args = o_f.decide_function(i, s)
ready_args = decide_args(args)
s[i] = decide_func(s[i], ready_args)
verify(s, i, st_nums, st_ops)

elif o_f.prior(s[i]) <= o_f.prior(st_ops[-1]):
if s[i] == '^' and st_ops[-1] == '^':
st_ops.append(s[i])
else:
try:
st_nums[-2] = o_f.bin_operate(st_nums[-2], st_nums[-1], st_ops[-1])
except Exception:
print('ERROR: not necessary element')
exit()
del st_nums[-1]
del st_ops[-1]
verify(s, i, st_nums, st_ops)

elif o_f.prior(s[i]) > o_f.prior(st_ops[-1]):
st_ops.append(s[i])


def decide_args(args):
ready_args = []
for s in args:
ready_args.append(decide_expression(s))

return ready_args
137 changes: 137 additions & 0 deletions final_task/calc/math_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from math import *

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Импортирование через звездочку может привести к конфликту имен или просто запутать программиста.
Я думаю, будет лучше просто сделать импорт библиотеки math

import math



def decide_func(func, ready_args):
if len(ready_args) == 0:
print('ERROR: no necessary arguments ')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В данном случае будет уместно использовать исключения.

exit()

elif len(ready_args) > 2:
print('ERROR: so many arguments')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В данном случае будет уместно использовать исключения.

exit()

elif func == 'abs':

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Огромное количество одинакого кода. Почему бы в данной ситуации не использовать словарь с маппингом функций, где ключ -- это название функции, а значение -- это сама функция?

functions_mapping = {
    "sin": math.sin,
    ...
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Очень хорошая вещь этот маппинг, жалко раньше не знал.

return abs(ready_args[0])

elif func == 'acos':
return acos(ready_args[0])

elif func == 'acosh':
return acosh(ready_args[0])

elif func == 'asin':
return asin(ready_args[0])

elif func == 'asinh':
return asinh(ready_args[0])

elif func == 'atan':
return atan(ready_args[0])

elif func == 'atanh':
return atanh(ready_args[0])

elif func == 'ceil':
return ceil(ready_args[0])

elif func == 'cos':
return cos(ready_args[0])

elif func == 'degrees':
return degrees(ready_args[0])

elif func == 'erf':
return erf(ready_args[0])

elif func == 'exp':
return exp(ready_args[0])

elif func == 'expm1':
return expm1(ready_args[0])

elif func == 'fabs':
return fabs(ready_args[0])

elif func == 'factorial':
return factorial(ready_args[0])

elif func == 'floor':
return floor(ready_args[0])

elif func == 'frexp':
return frexp(ready_args[0])

elif func == 'gamma':
return gamma(ready_args[0])

elif func == 'lgamma':
return lgamma(ready_args[0])

elif func == 'log10':
return log10(ready_args[0])

elif func == 'log1p':
return log1p(ready_args[0])

elif func == 'log2':
return log2(ready_args[0])

elif func == 'radians':
return radians(ready_args[0])

elif func == 'sin':
return sin(ready_args[0])

elif func == 'sinh':
return sinh(ready_args[0])

elif func == 'sqrt':
return sqrt(ready_args[0])

elif func == 'tan':
return tan(ready_args[0])

elif func == 'tanh':
return tanh(ready_args[0])

elif func == 'trunc':
return trunc(ready_args[0])

elif func == 'round':
if len(ready_args) == 1:
ready_args.append(0)
return round(ready_args[0], int(ready_args[1]))

elif func == 'log':
if len(ready_args) == 1:
ready_args.append(e)
return log(ready_args[0], ready_args[1])

elif len(ready_args) < 2:
print('ERROR: no necessary arguments or our function "' + s[i] + '"')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В данном случае будет уместно использовать исключения.

exit()

elif func == 'atan2':
return atan2(ready_args[0], ready_args[1])

elif func == 'fmod':
return fmod(ready_args[0], ready_args[1])

elif func == 'gcd':
return gcd(ready_args[0], ready_args[1])

elif func == 'hypot':
return hypot(ready_args[0], ready_args[1])

elif func == 'copysign':
return copysign(ready_args[0], ready_args[1])

elif func == 'pow':
return pow(ready_args[0], ready_args[1])

elif func == 'ldexp':
return ldexp(ready_args[0], ready_args[1])

else:
print('ERROR: not find function "' + func + '"')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В данном случае будет уместно использовать исключения.

exit()
Loading