Как бы сжать этот оператор if в Python?

#python #if-statement

#python #if-statement

Вопрос:

В настоящее время я создаю калькулятор на Python, и я столкнулся с небольшой проблемой: у меня есть 28 условий в моем операторе if-else:

 if operation0 == " " and operation1 == " " and operation2 == " ": # First operation is addition
    print(number0   number1   number2   number3)
elif operation0 == " " and operation1 == " " and operation2 == "*":
    print(number0   number1   number2 * number3)
elif operation0 == " " and operation1 == " " and operation2 == "^":
    print(number0   number1   number2 ** number3)
elif operation0 == " " and operation1 == "*" and operation2 == " ":
    print(number0   number1 * number2   number3)
elif operation0 == " " and operation1 == "*" and operation2 == "*":
    print(number0   number1 * number2 * number3)
elif operation0 == " " and operation1 == "*" and operation2 == "^":
    print(number0   number1 * number2 ** number3)
elif operation0 == " " and operation1 == "^" and operation2 == " ":
    print(number0   number1 ** number2   number3)
elif operation0 == " " and operation1 == "^" and operation2 == "*":
    print(number0   number1 ** number2 * number3)
elif operation0 == " " and operation1 == "^" and operation2 == "^":
    print(number0   number1 ** number2 ** number3)
elif operation0 == "*" and operation1 == " " and operation2 == " ": # First operation is multiplication
    print(number0 * number1   number2   number3)
elif operation0 == "*" and operation1 == " " and operation2 == "*":
    print(number0 * number1   number2 * number3)
elif operation0 == "*" and operation1 == " " and operation2 == "^":
    print(number0 * number1   number2 ** number3)
elif operation0 == "*" and operation1 == "*" and operation2 == " ":
    print(number0 * number1 * number2   number3)
elif operation0 == "*" and operation1 == "*" and operation2 == "*":
    print(number0 * number1 * number2 * number3)
elif operation0 == "*" and operation1 == "*" and operation2 == "^":
    print(number0 * number1 * number2 ** number3)
elif operation0 == "*" and operation1 == "^" and operation2 == " ":
    print(number0 * number1 ** number2   number3)
elif operation0 == "*" and operation1 == "^" and operation2 == "*":
    print(number0 * number1 ** number2 * number3)
elif operation0 == "*" and operation1 == "^" and operation2 == "^":
    print(number0 * number1 ** number2 ** number3)
elif operation0 == "^" and operation1 == " " and operation2 == " ": # First operation is exponentiation
    print(number0 ** number1   number2   number3)
elif operation0 == "^" and operation1 == " " and operation2 == "*":
    print(number0 ** number1   number2 * number3)
elif operation0 == "^" and operation1 == " " and operation2 == "^":
    print(number0 ** number1   number2 ** number3)
elif operation0 == "^" and operation1 == "*" and operation2 == " ":
    print(number0 ** number1 * number2   number3)
elif operation0 == "^" and operation1 == "*" and operation2 == "*":
    print(number0 ** number1 * number2 * number3)
elif operation0 == "^" and operation1 == "*" and operation2 == "^":
    print(number0 ** number1 * number2 ** number3)
elif operation0 == "^" and operation1 == "^" and operation2 == " ":
    print(number0 ** number1 ** number2   number3)
elif operation0 == "^" and operation1 == "^" and operation2 == "*":
    print(number0 ** number1 ** number2 * number3)
elif operation0 == "^" and operation1 == "^" and operation2 == "^":
    print(number0 ** number1 ** number2 ** number3)
else:
    print("Error")
  

Ничего из того, что я пробовал, не сработало, и я не смог найти на этом сайте ничего, что помогло бы мне сжать код. Такое количество повторяющихся elif неразумно, и любое сокращение будет оценено.

Комментарии:

1. Я думаю, что лучше всего было бы реализовать алгоритм маневровой площадки .

Ответ №1:

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: в решении могут использоваться различные концепции, которые недостаточно актуальны для объяснения здесь.

Чтобы получить приоритет, вам нужно будет правильно проанализировать входные данные. Для этого существует несколько методов; одним из распространенных является алгоритм маневровой площадки Дейкстры.
Поскольку это всего лишь пример, мы откажемся от хорошей практики (обработка ошибок, классы) для более сжатого кода.

Во-первых, нам нужно перечислить прецеденты. Более высокий приоритет означает, что оператор имеет более высокий приоритет, поэтому он выполняется раньше.

 precedences = {
    '^': 3,
    '*': 2, '/': 2,
    ' ': 1, '-': 1
}
  

Затем нам нужно связать действия с каждым оператором. Для этого мы можем использовать функции в operator модуле:

 from operator import pow, truediv, mul, add, sub
do = {
    '^': pow,
    '*': mul, '/': truediv,
    ' ': add, '-': sub
}
  

Наконец, нам нужно реализовать логику, которая решает, когда оценивать выражение. Во-первых, у нас на одно число больше, чем операция, поэтому мы помещаем его в стек:

 def shunt(numbers, operations):
    stack = [numbers.pop(0)]
    operators = []
  

Затем мы обрабатываем каждую пару оператор-число.

     while len(numbers):
        operator = operations.pop(0)
        precedence = precedences[operator]
  

Операция вычисляется (с использованием do словаря), когда она имеет более высокий приоритет (выполняется раньше), чем текущая операция. Мы удаляем левый и правый операнды из стека и выполняем поиск соответствующей функции do для оценки результата:

         while operators and precedences[operators[-1]] >= precedence:
            [left, right], stack[-2:] = stack[-2:], []
            stack.append(do[operators.pop()](left, right))
  

Затем мы добавляем текущий оператор и число в стеки:

         operators.append(operator)
        stack.append(numbers.pop(0))
  

После того, как все числа и операторы были израсходованы, мы оцениваем остальные операторы до тех пор, пока не останется только одно число, и возвращаем это:

     while len(stack) > 1:
        [left, right], stack[-2:] = stack[-2:], []
        stack.append(do[operators.pop()](left, right))
    return stack[0]
  

Собрать все это вместе (попробуйте онлайн!):

 from operator import pow, truediv, mul, add, sub

precedences = {
    '^': 3,
    '*': 2, '/': 2,
    ' ': 1, '-': 1
}

do = {
    '^': pow,
    '*': mul, '/': truediv,
    ' ': add, '-': sub
}

def shunt(numbers, operations):
    stack = [numbers.pop(0)]
    operators = []
    while len(numbers):
        operator = operations.pop(0)
        precedence = precedences[operator]
        while operators and precedences[operators[-1]] >= precedence:
            [left, right], stack[-2:] = stack[-2:], []
            stack.append(do[operators.pop()](left, right))
        operators.append(operator)
        stack.append(numbers.pop(0))
    while len(stack) > 1:
        [left, right], stack[-2:] = stack[-2:], []
        stack.append(do[operators.pop()](left, right))
    return stack[0]
  

Ответ №2:

Порядок операций делает это сложным, но не невозможным:

 # helper function to do an operation
def doop(num1, op, num2):
    if op == "^":
        return num1 ** num2
    if op == " ":
        return num1   num2
    if op == "-":
        return num1 - num2
    if op == "*":
        return num1 * num2
    if op == "/":
        return num1 / num2
    # if we don't recognize the operation then error
    raise Exception("Invalid operation.")

# have a list of sets with operator precedence
precedence = [
    {"^"},
    {"*", "/"},
    {" ", "-"}
]

# hard coded values for testing
nums = [1, 2, 3, 4]
ops = [" ", "-", "*"]
# this represents 1   2 - 3 * 4

# start at highest to lowest precedence
for prec in precedence:
    # we have to use a while loop to have manual control of `i`
    i = 0
    while i < len(ops):
        # store the current operation
        op = ops[i]
        # if the operation isn't in the current precedence level we skip it
        if op in prec:
            # we can get rid of the operation to evaluate it
            ops.pop(i)
            # we can merge the two numbers around the operation into one
            # by performing the calculation
            nums[i:i   2] = [doop(nums[i], op, nums[i   1])]
            # we need to decrease i so we don't skip over the next operation
            i -= 1
        i  = 1

if len(nums) != 1:
    raise Exception("Invalid operation count.")

print(nums[0]) # -9
  

Комментарии:

1. аплет, где объяснение

2. Я думаю, что более специализированное исключение будет работать лучше, например ArithmeticError .

Ответ №3:

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

 def compute(*operNums):
    operNums   = list(operNums)
    numbers    = operNums[::2]  # [number0,number1,number2,number3]
    operations = operNums[1::2] # [operation0,operation1,operation2]
    while operations:           # process list until all operations performed
        for op in ("^","**","*"," "):          # find highest priority operation
            if op not in operations: continue
            i = operations.index(op)           # index of operation
            operations.pop(i)                  # remove completed operation
            if   op in ["^","**"]: numbers[i] **= numbers.pop(i 1) # remove right side
            elif op == "*":        numbers[i]  *= numbers.pop(i 1) # left side number
            elif op == " ":        numbers[i]   = numbers.pop(i 1) # is replaced by result   
            else: return "ERROR"
    return numbers[0]

print(compute(1," ",2,"**",3,"*",5)) # 41
  

Ответ №4:

Вы могли бы использовать библиотеку операторов и попробовать что-то вроде

 from operator import pow, truediv, mul, add, sub  

operators = {
  ' ': add,
  '-': sub,
  '*': mul,
  '/': truediv
}

def calculate(s):
    if s.isdigit():
        return float(s)
    for c in operators.keys():
        left, operator, right = s.partition(c)
        if operator in operators:
            return operators[operator](calculate(left), calculate(right))

calc = input("Type calculation:n")
print("Answer: "   str(calculate(calc)))
  

Некоторые другие решения также доступны по адресу https://levelup.gitconnected.com/3-ways-to-write-a-calculator-in-python-61642f2e4a9a

Комментарии:

1. как и ответ Карла, не обрабатывает приоритет