Calculadora básica de python

Oct 20 2020

Tengo un joven amigo que está empezando a aprender Python en la escuela y me pidió que le diera una pequeña tarea. De ninguna manera soy un profesor ni un experto en Python, pero acepté.

Al principio pensé que sería divertido comenzar analizando un poco la entrada de la operación, como:

Enter your operation : 3+3

Pero le pareció un poco abrumador, así que acordamos separarlo en tres partes (primer número, operando y segundo número).

Hice una pequeña corrección pero me parece torpe y el objetivo del ejercicio es mostrarle algunas buenas prácticas.

Entonces aquí está mi 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

Hubiera querido hacer un bucle cuando number1o number2no sea válido floathasta que el usuario ingrese un valor válido, pero no encontré una manera limpia de hacerlo. Con mucho gusto aceptaría consejos sobre esto (aunque sé que esta no es una pregunta para este Stack Exchange, una buena forma Pythonic de hacer esto sería genial :)).

Respuestas

9 AryanParekh Oct 21 2020 at 04:59

Usa más funciones

Tiene una función calculate(), pero si ve que hace mucho más que calcular, esto hace que su código se vea irrazonablemente torpe. Pero hay una solución muy simple, use más funciones. ¿Y si su bucle principal pudiera verse como

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 

Esto facilita el mantenimiento de su programa.

continue cuando hay un error

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

Pregúntese, ¿por qué terminaría un programa si el usuario ingresa una entrada no válida? Dale otra oportunidad xD

Mantenga una sangría constante

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

Trate de mantener una sangría consistente, ya que ha usado 4espacios antes, no hay una buena razón para usarlos 8más tarde, podría confundir a las personas que lean el código más tarde.

Lógica de código 1

Consideremos esta entrada de muestra

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

Claramente, symbolestá mal. ¿Por qué tuve que ingresar el segundo número, solo para descubrir que cometí un error al ingresar el symbol? Debería haberme dicho de inmediato que mi símbolo era incorrecto, por lo que podría haberlo corregido.

Simplemente mueva el if symbol not in operandsenunciado para que quede junto a la entrada.

eval

Evaluar en Python

Esta sería la mayor mejora en su programa, ya que convierte entre 10 y 15 líneas de código en una.

La eval()función evalúa la expresión especificada, si la expresión es una declaración de Python legal, se ejecutará.

Eso suena familiar, ¿no estamos evaluando básicamente expresiones simples?

Usando eval, su parte de cálculo se vería así

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

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

Esto es lo que básicamente está pasando

result = eval("5+10")

Final

Aquí está el código con las mejoras.

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 es una alternativa a su código, es un poco más complejo pero también es más legible. Me las arreglé para hacer el bucle, pero es un poco difícil de seguir. Lo siento.

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


Consejos:

  • Divida las cosas en funciones:

Las funciones son solo contenedores para el código que se puede ejecutar, las funciones DEBEN hacer UNA y solo UNA cosa más en las funciones aquí .

  • Intente comentar su código, lo hace más fácil de leer y editar.

Esta función

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

sería mucho mejor con una explicación o lo que está pasando

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 f strings (esto requiere python 3.6 y superior)

f cadenas se usan así

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))
  • Intenta espaciar tu código

Créame, esto hace que su código sea más fácil de leer y comprender.

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