Базовый калькулятор Python

Oct 20 2020

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

Сначала я подумал, что было бы интересно начать с небольшого анализа ввода операции, например:

Enter your operation : 3+3

Но это показалось ему немного подавляющим, поэтому мы договорились разделить его на три части (первое число, операнд и второе число).

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

Итак, вот мой код:

calculate = True
while calculate:
    try:
        number1 = float(input("Enter the first number : "))
    except ValueError:
            print("Incorrect value")
            exit()
    symbol = input("Enter the operation symbol (+,-,/,*,%) : ")
    try:
        number2 = float(input("Enter the second number : "))
    except ValueError:
            print("Incorrect value")
            exit()
    operande = ["+", "-", "*", "/", "%"]
    resSentence = "Result of operation \"{} {} {}\" is :".format(number1, symbol, number2)
    if symbol not in operande:
        print("Incorrect symbol")
    elif symbol == "+":
        print(resSentence, number1 + number2)
    elif symbol == "-":
        print(resSentence, number1 - number2)
    elif symbol == "*":
        print(resSentence, number1 * number2)
    elif symbol == "/":
        print(resSentence, number1 / number2)
    elif symbol == "%":
        print(resSentence, number1 % number2)
    restart = input("Do you want to do another calcul (Y/n) ? ")
    while restart.lower() != "y" and restart.lower() != "n":
        print(restart.lower(), restart.lower(), restart.lower()=="n")
        restart = input("Please, enter \"y\" to continue or \"n\" to exit the program : ")
    if restart.lower() == "n":
        calculate = False

Я бы хотел создать цикл, когда он number1или number2недействителен, floatпока пользователь не введет действительное значение, но я не нашел чистого способа сделать это. Я с радостью приму советы по этому поводу (хотя я знаю, что это не вопрос для этого Stack Exchange, хороший питонический способ сделать это было бы круто :)).

Ответы

9 AryanParekh Oct 21 2020 at 04:59

Используйте больше функций

У вас есть функция calculate(), но если вы видите, что она делает гораздо больше, чем просто вычисляет, это делает ваш код неоправданно неуклюжим. Но есть очень простое решение - использовать больше функций. Что, если бы ваш основной цикл мог выглядеть как

while True:
    number1,number2,operand = take_input()
    result = calculate(number1,number2,operand)
    print(f"Answer : {numebr1} {operand} {number2} = {result}")
    if input("Do you want to play again? (y/n): ").lower() == 'n':
        break 

Это упрощает поддержку вашей программы.

continue когда есть ошибка

try:
    number1 = float(input("Enter the first number : "))
except ValueError:
        print("Incorrect value")
        exit()

Спросите себя, зачем программе завершаться, если пользователь вводит неверный ввод? Дай ему еще один шанс xD

Сохраняйте постоянный отступ

try:
    number2 = float(input("Enter the second number : "))
except ValueError:
            print("Incorrect value")
            exit()

Старайтесь поддерживать последовательный отступ, поскольку вы использовали 4пробелы раньше, нет веских причин для использования 8позже, это может просто сбить с толку людей, которые прочитают код позже.

Кодовая логика 1

Давайте рассмотрим этот пример ввода

Enter the first number : 1
Enter the operation symbol (+,-,/,*,%) : I like python
Enter the second number : 2
Incorrect symbol

Ясно, что symbolэто неправильно. Почему мне пришлось вводить второй номер, чтобы узнать, что я ошибся при вводе symbol? Он должен был сразу сказать мне, что мой символ неправильный, чтобы я мог его исправить.

Просто переместите if symbol not in operandsоператор так, чтобы он располагался рядом с полем ввода.

eval

Eval в Python

Это будет самым большим улучшением в вашей программе, поскольку она преобразует около 10-15 строк кода в одну.

eval()Функция вычисляет заданное выражение, если выражение является юридическим заявлением Python, он будет выполнен.

Звучит знакомо, разве мы не оцениваем в основном простые выражения?

Используя eval, ваша расчетная часть будет выглядеть как

result = eval(f"{number1}{operand}{number2}")

Пример, number1 = 5,number2 = 10, operand = '+'

Вот что в основном и происходит

result = eval("5+10")

Финал

Вот код с улучшениями

def take_input():
    err_msg = "Invalid input"
    operands = ['+','-','*','/','%']
    try:
        num1 = float(input("Enter number 1: "))
    except Exception:
        print(err_msg)
        return take_input()
    try:
        num2 = float(input("Enter number 2: "))
    except Exception:
        print(err_msg)
        return take_input()

    print("Operands: " + ', '.join(x for x in operands))
    try:
        operand = input("Enter operand: ")
    except Exception:
        print(err_msg)
        return take_input()

    if operand not in operands:
        print(err_msg)
        return take_input()

    return num1,num2,operand

def calculate(num1,num2,operand):
    return eval(f"{num1}{operand}{num2}")


def mainloop():
    while True:
        num1,num2,operand = take_input()
        result = calculate(num1,num2,operand)
        print(f"Answer: {result}")
        if input("Do you want to play again? (y/n): ").lower() == 'n':
            break

mainloop()
5 Deep_Thoughts Oct 20 2020 at 21:54

Это альтернатива вашему коду, он немного сложнее, но при этом более читабелен. Мне удалось сделать петлю, но за ней сложно уследить. Сожалею.

running = True
# Break Things up into functions each function does one single thing

def calculate(inputOne, operand, inputTwo):
    """
    Calculates inputOne operand and inputTwo
    """

    if operand == "+":
        return inputOne + inputTwo
    elif operand == "-":
        return inputOne - inputTwo
    elif operand == "*":
        return inputOne * inputTwo
    elif operand == "/":
        return inputOne / inputTwo
    elif operand == "%":
        return inputOne % inputTwo

def askInput():
    """
    Asks for a number until a number is given checks if each one is valid
    """

    isValid = [False, False, False] # none of the numbers are validated yet
    number1, symbol, number2 = ["", "", ""]
    
    # Here is a good implementation of the loop, it is kind of complex though
    while True:
        try:
            if not isValid[0]: # Asks for number1 if it is not valid
                number1 = int(input("Enter the first number : "))
                isValid[0] = True

            if not isValid[1]: # This is added functionality because there was a loophole in your program
                symbol = input("Enter the operation symbol (+,-,/,*,%) : ") # use tuples whenever possible
                supportedOperands = ("+", "-", "/", "*", "%")

                if symbol not in supportedOperands:
                    raise ValueError

                isValid[1] = True

            if not isValid[2]: # Asks for number2 if it is not valid
                number2 = int(input("Enter the second number : "))
                isValid[2] = True
            break
        
        except ValueError:
            continue # this just restarts the whole thing
    
    return number1, symbol, number2



def continueApp():
    """
    Checks if the input to restart is valid
    """
    restart = input("Do You want to do another calculation (Y/n) ? ").lower()

    while True:
        if restart == "y":
            return True
        elif restart == "n":
            return False
        else:
            restart = input("Please, enter \"y\" to continue or \"n\" to exit the program : ").lower()

while running:

    numberOne, operand, numberTwo = askInput()
    answer = calculate(numberOne, operand, numberTwo)
    resSentence = f"Result of operation {numberOne} {operand} {numberTwo} is : {answer}"
    print(resSentence)

    if continueApp():
        pass
    else:
        running = False
exit()


Подсказки:

  • Разбейте вещи на функции:

Функции просто контейнеры для кода , которые могут быть выполнены, функции должны сделать ОДИН и только ОДИН вещи больше функций здесь .

  • Пожалуйста, попробуйте прокомментировать свой код, это облегчит чтение и редактирование.

Эта функция

def calc():
    x = 1
    y = 12
    return (((x+y)/x)**y)+(3*x+4*y) # Please don't write like this in any case

было бы намного лучше с объяснением или что происходит

def calc():
    """
    Accepts: Nothing
    Does: Adds X and Y, then divides it by X to the power of Y
          then it adds  it to X multiplied by three and 4 multiplied by Y
    Returns: integer (the result of Does) ^^^^^
    """
    x = 1
    y = 12
    return ((x+y)/x**y)+(3*x+4*y) # Again, please don't write code like this
  • Используйте строки f (для этого требуется Python 3.6 и выше)

f строки используются так

value = "12"
print(f"Number {value} is an example of an f string") 

# Versus

print("Number {} is an example of an f string".format(value))
  • Попробуйте выделить свой код

Поверьте, это облегчает чтение и понимание вашего кода.

def calc():
    """
    Accepts: Nothing
    Does: Adds X and Y, then divides it by X to the power of Y
          then it adds  it to X multiplied by three and 4 multiplied by Y
    Returns: integer (the result of Does) ^^^^^
    """
    x = 1
    y = 12
    ans = (x + y) / (x ** y)
    ans += (3 * x) + (4 * y) # just adds ans to the right side of the operator
    return ans