Упростить код на Python
Рябят, кто сможет покритиковать / помочь упростить монстрообразный код - изучаю питон, сейчас сделал задание по функциям, делал сам, но ощущаю, что код не лаконичный, наверняка можно было сделать проще, но не могу сообразить как, видимо не хватает знаний.
Задание: Напишите программу, которая принимает арифметическое выражение в качестве аргумента и выводит результат этого выражения.
Примечание: Необходимо использовать функции. Программа должна поддерживать следующие арифметические операции: +, -, /, *, %(получение процента от числа), **(возведение в квадрат), **х(возведение в степень числа х). Запрещено подключать дополнительные модули. Для вывода результата необходимо использовать функцию print().
Значения для самостоятельной проверки: Подставьте "Входные данные" в свою программу и сравните результат с выходными данными.
- Входные данные: 1+9. Выходные значения: 10.
- Входные данные: 100%. Выходные значения: 1.0.
- Входные данные: 4**. Выходные значения: 16.
- Входные данные: 9**3. Выходные значения: 729.
Вот именно из-за 2 и 3 пункта пришлось делать именно так, как я написал т.к. получается, что мы передаем в функцию выражение: "100%", на выходе должно быть 1.0, т.е. получается, что передаем число и оператор, а второго числа нет и просто вывести результат выражения, как с 1 пунктом не получается. Конечно, если бы в функцию отдельно передавались числа и оператор как аргументы через запятую, то все было бы куда проще, я бы сразу условие написал, если оператор такой, значит делаем так, если второго аргумента нет, значит делаем так, но условие вот такое и код получился длинный: Ссылка на гитхаб: https://github.com/Magva7/Python_my_progs/blob/main/function/calc_func.py
# vyrajenie = '1+9'
# vyrajenie = '11-99'
vyrajenie = '11/2'
# vyrajenie = '4**'
# vyrajenie = '9**3'
# vyrajenie = '100%3'
# vyrajenie = '100%'
vvod_str = str(vyrajenie)
vvod_list = list(vyrajenie) # переводим введенное выражение в списокр
def calc(vyrajenie):
if vvod_list.count('+') != 0: # проверяем, если ли в списке элемент +
plus(vyrajenie) # запускаем функцию plus
elif vvod_list.count('-') != 0: # проверяем, если ли в списке элемент +
minus(vyrajenie) # запускаем функцию минус
elif vvod_list.count('/') != 0: # проверяем, если ли в списке элемент /
delenie(vyrajenie) # запускаем функцию деление
elif vvod_list.count('*') != 0: # проверяем, если ли в списке элемент *
umnoj_stepen(vyrajenie) # запускаем функцию umnoj_stepen
elif vvod_list.count('%') != 0: # проверяем, если ли в списке элемент %
ostatok(vyrajenie) # запускаем функцию ostatok
def plus(vyrajenie): # передали в функцию введенное выражение
if vvod_list.count('+') != 0: # проверяем, если ли в списке элемент +
index_operator = vvod_list.index('+') # записываем индекс элемента-оператора +
sleva = ''
sprava = ''
i = 0
while i < index_operator: # до тех пор, пока у нас индекс текущего элемента меньше
# индекса элемента, который оператор (это элемент, который +, * или что-то другое)
sleva += vvod_list[i] # мы добавляем в то, что справа элементы до оператора
i += 1
i += 1
while i < len(vvod_list): # до тех пор пока i меньше длины списка, т.е. до
# последнего элемента
sprava += vvod_list[i] # мы добавляем в то, что слева элементы после оператора
i += 1
result = int(sleva)+int(sprava)
print(result)
return result
def minus(vyrajenie): # передали в функцию введенное выражение
if vvod_list.count('-') != 0: # проверяем, если ли в списке элемент -
index_operator = vvod_list.index('-') # записываем индекс элемента-оператора -
sleva = ''
sprava = ''
i = 0
while i < index_operator: # до тех пор, пока у нас индекс текущего элемента меньше
# индекса элемента, который оператор (это элемент, который +, * или что-то другое)
sleva += vvod_list[i] # мы добавляем в то, что справа элементы до оператора
i += 1
i += 1
while i < len(vvod_list): # до тех пор пока i меньше длины списка, т.е. до
# последнего элемента
sprava += vvod_list[i] # мы добавляем в то, что слева элементы после оператора
i += 1
result = int(sleva)-int(sprava)
print(result)
return result
def delenie(vyrajenie): # передали в функцию введенное выражение
if vvod_list.count('/') != 0: # проверяем, если ли в списке элемент -
index_operator = vvod_list.index('/') # записываем индекс элемента-оператора -
sleva = ''
sprava = ''
i = 0
while i < index_operator: # до тех пор, пока у нас индекс текущего элемента меньше
# индекса элемента, который оператор (это элемент, который +, * или что-то другое)
sleva += vvod_list[i] # мы добавляем в то, что справа элементы до оператора
i += 1
i += 1
while i < len(vvod_list): # до тех пор пока i меньше длины списка, т.е. до
# последнего элемента
sprava += vvod_list[i] # мы добавляем в то, что слева элементы после оператора
i += 1
result = int(sleva)/int(sprava)
print(result)
return result
def umnoj_stepen(vyrajenie): # передали в функцию введенное выражение
if vvod_list.count('*') != 0: # проверяем, если ли в списке элемент *
index_operator = vvod_list.index('*') # записываем индекс элемента-оператора *
if vvod_list[index_operator+1] == '*': # если следующий за ним элемент тоже *,
# значит у нас возведение в степень
sleva = ''
sprava = ''
i = 0
while i < index_operator: # до тех пор, пока у нас индекс текущего элемента меньше
# индекса элемента, который оператор (это элемент, который первая *)
sleva += vvod_list[i] # мы добавляем в то, что справа элементы до оператора
i += 1
i += 2
while i < len(vvod_list): # до тех пор пока i меньше длины списка, т.е. до
# последнего элемента
sprava += vvod_list[i] # мы добавляем в то, что слева элементы после
# второго оператора *
i += 1
if sprava != '': # если у нас справа не пусто, значит у нас возведение в
# степень одного числа на другое
result = int(sleva) ** int(sprava)
else: # если же справа пусто, значит мы возводим число справа в квадрат
result = int(sleva) ** 2
else: # если следующий за ним элемент не тоже *, значит у нас просто умножение
sprava = ''
sleva = ''
i = 0
while i < index_operator: # до тех пор, пока у нас индекс текущего элемента меньше
# индекса элемента, который оператор (это элемент, который первая *)
sprava += vvod_list[i] # мы добавляем в то, что справа элементы до оператора
i += 1
i += 1
while i < len(vvod_list): # до тех пор пока i меньше длины списка, т.е. до
# последнего элемента
sleva += vvod_list[i] # мы добавляем в то, что слева элементы после
# второго оператора *
i += 1
result = int(sprava) * int(sleva)
# print('sprava = ', sprava)
# print('sleva = ', sleva)
print(result)
return result
def ostatok(vyrajenie): # передали в функцию введенное выражение
if vvod_list.count('%') != 0: # проверяем, если ли в списке элемент *
index_operator = vvod_list.index('%') # записываем индекс элемента-оператора *
sleva = ''
sprava = ''
i = 0
while i < index_operator: # до тех пор, пока у нас индекс текущего элемента меньше
# индекса элемента, который оператор (это элемент, который %)
sleva += vvod_list[i] # мы добавляем в то, что справа элементы до оператора
i += 1
i += 1
while i < len(vvod_list): # до тех пор пока i меньше длины списка, т.е. до
# последнего элемента
sprava += vvod_list[i] # мы добавляем в то, что слева элементы после
# второго оператора *
i += 1
if sprava != '': # если у нас справа не пусто, значит у нас остаток от
# деления одного числа на другоев
result = float(sleva) % float(sprava)
else: # если же справа пусто, значит делаем остаток числа от самого себя
result = float(sleva) / float(sleva)
print(result)
return result
calc(vyrajenie) # запускаем нашу функцию
Ответы (5 шт):
Я вот так вот писал шифратор и дешифратор,обрати внимание на часть которую я выделил,не уверен что тебе может помочь,но это может упростить твое решение . Если ты сразу спросишь че надо делать. По заданию впрн тебе надо спросить изначально,что надо, а потом в зависимости от этого,чтобы код пошел по той или иной ветке решения Заранее извини,если это не поможет. Я только начинаю.Но стараюсь
***slov = int(input("Введи количество слов которые надо либо зашифровать или расшифровать:"))
while slov > 0:
slov-=1
cryptMode = input("Выбери че хочешь делать: [Ш]ифрование|[Д]ешифрование: ").upper()
if cryptMode not in ['Ш', 'Д']:
print("Ошибка, режим не найден!")
raise SystemExit***
startMessage = input("Введите сообщение: ").upper()
keyMessage = input("Введите номер ключа: ")
def encryptdecrypt(mode, message, key, final=""):
key *= len(message) // len(key) + 1
for index, symbol in enumerate(message):
if mode == 'Ш':
temp = ord(symbol) + int(key[index]) - 1
else:
temp = ord(symbol) - int(key[index]) - 9
final += chr(temp % 30 + ord('А'))
return final
print("Final message:", encryptdecrypt(cryptMode, startMessage, keyMessage))
print("жмакай Enter!")
k=input("Пожалуйста,без пробелов ,по слову вводи")
По мотивам вашего кода попытался написать код разбора выражения просто и лаконично, используя максимально простые конструкции языка.
SYMBOLS = '+-*/%' # поддерживаемые операции
DIGITS = '1234567890' # цифры
ACCEPTABLE = SYMBOLS + DIGITS # вообще допустимые символы во входной строке
def calc(text):
groups = [] # сюда будем группировать символы операндов и операции
for char in text:
if char not in ACCEPTABLE: # игнорируем недопустимые символы
continue
if (len(groups)==0 or
(char in DIGITS and groups[-1][-1] in SYMBOLS) or
(char in SYMBOLS and groups[-1][-1] in DIGITS)
): # создаём новую группу при смене символа с цифры на операцию (и обратно)
groups.append([char])
else: # иначе дописываем к последней группе
groups[-1].append(char)
if len(groups) < 2 or len(groups) > 3: # допустимые операции состоят из 2 или 3 элементов
return None # так что выходим если это не так
for i in range(len(groups)): # так как groups содержит списки символов
groups[i] = ''.join(groups[i]) # собираем их в строки
operator = groups[1] # операция всегда в первом элементе списка
if operator not in ['+','-','*','/','**','%']: # проверяем на допустимость операции
return None # и выходим если неизвестная операция
left = int(groups[0]) # левый операнд в нулевом элементе списка
if len(groups) == 2 and operator == '**': # упростим себе жизнь добавив правый операнд
groups.append('2') # для возведения в квадрат
if len(groups) == 3:
right = int(groups[2]) # правый операнд во втором элементе списка
if operator == "+" : return left + right
elif operator == "-" : return left - right
elif operator == "*" : return left * right
elif operator == "/" : return left / right
elif operator == "%" : return left % right
elif operator == "**": return left ** right
else: return None
elif operator == '%':
return float(left) / 100
Но если кратко, то нижеприведённая лямбда-функция считает то же самое. Только что на ошибки не проверяет.
calc = lambda t: eval(t+'2' if t[-1]=='*' else t[:-1]+'/100' if t[-1]=='%' else t)
Напишите программу, которая принимает арифметическое выражение в качестве аргумента и выводит результат этого выражения.
в качестве извлечения математического оператора используем метод "split" для строк
ограничения: только один арифметический знак в строке, нет проверок на недопустимые символы
def simplyCalc(expr):
new=[]
for char in expr:
if char =='*':
if expr.find('*') != expr.rfind('*'): #если встретили знак умножения "*", то проверяем, что он единственный
new=expr.split('**')
num1=int(new[0])
if new[1].isdigit(): #если после '**' нет цифры, то понимаем, что это возведение в квадрат
num2 =int(new[1])
else:
num2 =2
x = num1**num2
else:
new=expr.split('*')
num1=int(new[0])
num2 =int(new[1])
x=num1*num2
elif char =='+':
new=expr.split('+')
num1 = int(new[0])
num2 = int(new[1])
x = num1+num2
elif char =='-':
new=expr.split('-')
num1 = int(new[0])
num2 = int(new[1])
x = num1-num2
elif char =='/':
new=expr.split('/')
num1 = int(new[0])
num2 = int(new[1])
x = num1/num2
elif char =='%':
new=expr.split('%')
num1 = int(new[0])
x=float(num1) / 100
return x
s = '11%'
print(simplyCalc(s))
print('-----End------')
Проверки на соответствие формату +уведомления
VR = list('1+9')
# VR = list('100%')
# VR = list('4**')
# VR = list('9**3')
# VR = list('19/3')
SYMBOLS = list('+-*/%') # поддерживаемые операции
DIGITS = list('1234567890') # цифры
def exception(s):
if s == 0:
n='Не допустимый символ'
if s == 1:
n='Не допустимый формат операции'
if s == 2:
n='Нет арифметической операции ' + ', '.join(SYMBOLS)
print (n)
exit ()
def calc(s): # проверив что все соответствует формату считаем средставами питона
cmd = r'print({})'.format( "".join(map(str, s)) )
exec(cmd)
def format(x,z): #проверки по формату
ACCEPTABLE=SYMBOLS.copy()
ACCEPTABLE.extend(DIGITS) # все поддерживаемые
index_max=len(VR)-1
for char in VR:
if ACCEPTABLE.count(char) == 0: #проверяем поддерживаемые операции
exception(0)
if x == '%' and z == 1 and VR[index_max] == '%':
print ('%(получение процента от числа)')
VR.pop() #удаляем последний символ
n = float("".join(map(str, VR))) / 100
print (n)
elif (x in '+' '-' '/' '*') and z == 1 and (VR[0] in DIGITS) and (VR[index_max] in DIGITS):
print('(операции +-/*)')
n=calc(VR)
elif x == '*' and z == 2:
if (VR[index_max] in DIGITS):
print('**х(возведение в степень числа х)')
n=calc(VR)
else:
print('**(возведение в квадрат)')
VR.append(2) #добавляем 2 для простоты
n=calc(VR)
else:
exception(1)
def solve(VR):
сountchar=0
for char in SYMBOLS:
if VR.count(char) > 0: #проверяем поддерживаемые операции
сountchar+=1
format(char, VR.count(char)) # какое действие выполняется, формат выражения
break
if сountchar < 1:
exception(2)
solve(VR)
Поскольку тут инспекция кода и никто не обратил внимание на это, то добавлю замечания не относящиеся к логике. Все рекомендации взяты из PEP.
Первое, что бросается в глаза - это конечно же комментарии на каждой строке. Так делать не надо по нескольким причинам:
- затрудняется чтение самого кода
- очень часто не соблюдается длина строки в 79 символов PEP 8 - максимальная рекомендованная длина
- так же в PEP 8 указано, что длина строк документации не должна превышать 72 символа
Для понимания, как комментировать код на python существует PEP 257 (en), PEP 257 (ru)
Безбожный нэйминг, честно, переменные и функции не надо называть в транслите, функцию начните с глагола (что делает?). Примеры:
vvod_str->input_strvyrajenie->expressionplus->add
За тем, как это соблюдать, обращаемся снова к документации PEP 8 (en), PEP 8 (ru)
Еще обратил внимание на функцию
print()внутри ваших функций. Есть такое понятие - чистая функция, под которым понимаются функции, не производящие никаких наблюдаемых побочных эффектов, только возвращающие результат. То есть, есть только вход и выход, и нет стандартного ввода или вывода, нет измений объектов выше зоны видимости самой функции (не трогают глобальные переменные и не изменяют их) и т. д. Если убрать из функцийprint()и сделать их чистыми, то результат работы функции надо выводить через стандартный вывод, т.е.
print(calc(vyrajenie))
- Если в функции существует вариант, когда функция ничего не возвращает, то необходимо явно указывать
None. Возьму для примера вашуostatok()
def ostatok(vyrajenie): # передали в функцию введенное выражение
if vvod_list.count('%') != 0:
.....
result = float(sleva) / float(sleva)
return result
else:
return None
Опять же данный пункт относится к PEP 8 рекомендации
Вообще, существует расширения для множества IDE, которые позволяют не задумываться о соблюдении указанных выше моментов. Их просто надо установить и использовать.
По логике, остальные ответы раскрывают ваше тему.
UPD
Решил добавить свой вариант для python 3.10 с конструкцией match-case. Цель была показать возможность использования
def prepare_input(user_input:str):
symbols = "+-/*"
result = {}
for symbol in symbols:
if symbol in user_input:
operation = symbol
user_list = user_input.split(operation)
if len(user_list) == 2:
try:
result["operation"] = operation
result["left"] = int(user_list[0].strip())
result["right"] = int(user_list[1].strip())
return result
except:
print("inncorrect input")
else:
return None
def calculate(values:dict):
if values:
operation, a, b = values["operation"], values["left"], values["right"]
match operation:
case "+": return a + b
case "-": return a - b
case "*": return a * b
case "/": return a / b
case _: return None
else:
return None
# tests
a = ["10 + 11", "10 / 11", "10 - 11", "10 * 11"]
for i in a:
expression = prepare_input(i)
print(calculate(expression))