Calculadora python básica

Oct 20 2020

Tenho um jovem amigo que está começando a aprender Python na escola e pediu-me que lhe desse uma pequena tarefa. Não sou de forma alguma professor nem especialista em Python, mas aceitei.

No início, pensei que seria divertido começar analisando um pouco a entrada da operação, como:

Enter your operation : 3+3

Mas pareceu um pouco opressor para ele, então concordamos em separar em três partes (primeiro número, operando e segundo número).

Fiz uma pequena correção, mas acho desajeitada e o objetivo do exercício é mostrar a ele algumas boas práticas.

Então, aqui está o meu código:

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

Eu gostaria de fazer um loop quando number1ou number2não é válido floataté que o usuário insira um valor válido, mas não encontrei uma maneira limpa de fazer isso. Eu aceitaria de bom grado conselhos sobre isso (embora eu saiba que essa não é uma pergunta para este Stack Exchange, uma boa maneira Pythônica de fazer isso seria legal :)).

Respostas

9 AryanParekh Oct 21 2020 at 04:59

Use mais funções

Você tem uma função calculate(), mas se perceber que ela faz muito mais do que apenas calcular, isso fará com que seu código pareça excessivamente desajeitado. Mas existe uma solução muito simples, use mais funções. E se o seu loop principal pudesse ser parecido com

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 

Isso torna mais fácil manter seu programa.

continue quando há um erro

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

Pergunte a si mesmo, por que um programa seria encerrado se o usuário inserisse uma entrada inválida? Dê a ele uma outra chance xD

Manter indentação consistente

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

Tente manter uma indentação consistente, já que você usou 4espaços antes, não há uma boa razão para usar 8depois, isso pode apenas confundir as pessoas que lerem o código mais tarde.

Código lógico 1

Vamos considerar este exemplo de entrada

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

Claramente, o symbolestá errado. Por que eu tive que inserir o segundo número, apenas para descobrir que cometi um erro ao inserir o symbol? Ele deveria ter me dito imediatamente que meu símbolo estava incorreto, então eu poderia ter corrigido.

Basta mover a if symbol not in operandsinstrução para que fique ao lado da entrada.

eval

Eval em Python

Essa seria a maior melhoria em seu programa, já que converte cerca de 10-15 linhas de código em uma.

A eval()função avalia a expressão especificada, se a expressão for uma instrução Python válida, ela será executada.

Isso parece familiar, não estamos basicamente avaliando expressões simples?

Usando eval, sua parte de cálculo pareceria

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

Exemplo, number1 = 5,number2 = 10, operand = '+'

Isso é o que basicamente está acontecendo

result = eval("5+10")

Final

Aqui está o código com as melhorias

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

Esta é uma alternativa ao seu código, é um pouco mais complexo, mas também é mais legível. Eu consegui fazer o loop, mas é meio difícil de seguir. Desculpa.

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()


Dicas:

  • Divida as coisas em funções:

Funções são apenas recipientes para código que pode ser executado, funções DEVEM fazer UMA e apenas UMA coisa a mais nas funções aqui .

  • Tente comentar sobre o seu código, torna-o mais fácil de ler e editar.

Esta função

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

seria muito melhor com uma explicação ou o que está acontecendo

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
  • Use strings f (requer Python 3.6 e superior)

strings f são usadas assim

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))
  • Tente espaçar seu código

Acredite em mim, isso torna seu código mais fácil de ler e entender.

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