1
\$\begingroup\$

I've been studying Python for about a month and I'm focusing on back-end development.

I've developed a simple program with a menu that includes a calculator and a guessing game. I would appreciate feedback on:

  • Code organization
  • Best practices
  • Possible improvements to the structure

Any suggestions are appreciated!

import random 

def calculadora():
    while True:
        print("+ soma")
        print("- subtração")
        print("/ divisão")
        print("* multiplicação")
        
        num1 = float(input("digite um número: "))
        num2 = float(input("digite outro número: "))
        
        operacao = input("Que tipo de conta deseja fazer? ")
        
        match operacao:
            case "+":
                res = num1 + num2
            case "-":
                res = num1 - num2
            case "*":
                res = num1 * num2
            case "/":
                if num2 == 0:
                    print("não existe divisão por 0")
                    continue
                else:
                    res = num1 / num2
            case _:
                print("operação inválida")
                continue
        
        print(f"o resultado é {res}")
        
        opcao_calc = input("deseja fazer mais contas? ")
        
        if opcao_calc.strip().lower() in ["não", "nao"]:
            print("adeus!")
            break

def joguinho():
    while True:
        #define o número aleatório do jogo
        num_jog = random.randint(1,1000)
        
        while True:
            #serve para informar ao jogador o intervalo de números
            print("número natural(0,1,2,...) entre 1 e 1000")
            
            #serve pra perguntar se o jogador acerta o número
            opcao_jog = int(input("Vamos ver se você acerta o número: "))
            
            #serve como forma de dica para o jogador
            if opcao_jog > num_jog:
                print("número menor")
            elif opcao_jog < num_jog:
                print("número maior")
            else:
                print("ACERTOU!!")
                break
        
        #pergunta seo jogador deseja jogar mais uma partida
        opcao2 = input("deseja jogar mais uma rodada?")   
        if opcao2.strip().lower() in ["não","nao"]:
            print("Adeus, volte sempre!")
            break
        
def adeus():
    print("Muito obrigado por usar o programa. Adeus!")
    
def menu():
    while True:
        print("Bem-vindo(a)!")
        print("O que deseja fazer?")
        print("1) usar a calculadora?")
        print("2) jogar um joguinho?")
        print("3) sair do programa?")
        
        opcao_menu = float(input("digite 1, 2 ou 3: "))
        if opcao_menu == 1:
            calculadora()
        elif opcao_menu == 2:
            joguinho()
        elif opcao_menu == 3:
            adeus()
            break
        elif opcao_menu == 3.14:
            print("Calma... PI?")
            print("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679")
            print("Gustavo diz:  Muito obrigado a todos que usaram o programa, que Deus abençoe a vida de vocês!")
            break
        
menu()
\$\endgroup\$
0

4 Answers 4

3
\$\begingroup\$

Exception handling

In joguinho you never handle the ValueError that may result from converting the string returned by input to an int. Never trust your user!

Functions

Inside the same function, the inner while loop probably should be a function itself.

__main__ guard

To avoid execution on importation, you should guard the call of menu.

if __name__ == '__main__':
    menu()

Invoking operations

You use a match statement to handle dispatching the various operations. I think this can be more cleanly structured using a dictionary of operations.

        print("+ soma")
        print("- subtração")
        print("/ divisão")
        print("* multiplicação")
        
        num1 = float(input("digite um número: "))
        num2 = float(input("digite outro número: "))
        
        operacao = input("Que tipo de conta deseja fazer? ")
        
        match operacao:
            case "+":
                res = num1 + num2
            case "-":
                res = num1 - num2
            case "*":
                res = num1 * num2
            case "/":
                if num2 == 0:
                    print("não existe divisão por 0")
                    continue
                else:
                    res = num1 / num2
            case _:
                print("operação inválida")
                continue
        
        print(f"o resultado é {res}")

Revised:

Your errors should probably also be printed to sys.stderr.

        operations = {
            '+': operator.add,
            '-': operator.sub,
            '*': operator.mul,
            '/': operator.div
        }

        print("+ soma")
        print("- subtração")
        print("/ divisão")
        print("* multiplicação")
        
        num1 = float(input("digite um número: "))
        num2 = float(input("digite outro número: "))
        
        operacao = input("Que tipo de conta deseja fazer? ")
        
        try:
            print(f"o resultado é {operations[operacao](num1, num2)}")
        except KeyError:
            print("operação inválida", file=sys.stderr)
        except ZeroDivisionError:
            print("não existe divisão por 0", file=sys.stderr)

This makes it very easy to add operations.

        operations = {
            '+': operator.add,
            '-': operator.sub,
            '*': operator.mul,
            '/': operator.div,
            '%': operator.mod,
            '^': operator.pow
        }
\$\endgroup\$
0
3
\$\begingroup\$

Some additional suggestions:

User Input

As mentioned, you have several places where you are inputting what is supposed to be a valid number but are not handling possible ValueError exceptions. You should consider having a generalized function for inputting numbers that performs the required inputting and validation. For example:

def input_number(prompt: str) -> float:
    """Input a valid number."""
    while True:
        try:
            return float(input(prompt))
        except ValueError:
            print('Invalid input; Please enter a valid number.')

You could have a similar function, for example:

def input_choice(prompt: str, choices: list[str]) -> str:
    ...

You pass to this a list of valid lower-case responses as argument choices. When asking the user a question that requires a yes or no answer, you would pass as ["não", "nao", "sim"] as choices. Any other response results in the prompt being re-issued. Thus, you are limiting the possible responses the user may enter to these specific values.

Missing Menu Item

You program accepts 3.14 as a possible response to your initial menu of choices, yet the user has no way of knowing that this choice is possible.

adeus Function

This is a very simple function of a single line that is called only in one place. The logic would be clearer if you remove this function definition and replace the call to this function with the function's body, that is, the print statement.

Use case statement in Function menu

Consider replacing the sequence of if/elif statements with a case statement just like you are doing in function calculadora.

\$\endgroup\$
2
\$\begingroup\$

In addition to the good suggestions from Chris, here are a few more considerations.

Input checking

It is great that you cleanly handle the divide by zero.

Since your code has a lot of input from the user, consider taking advantage of the pyinputplus module. It handles many common situations.

Documentation

The PEP 8 style guide recommends adding docstrings for functions and at the top of your code.

Feature

For the number guessing game, you could add a feature where you limit the number of guesses to something like 10. If the user does not guess the correct number in 10 tries, you could end the game.


I wish I could offer more advice about naming, comments and messages to the user, but I only understand English.

\$\endgroup\$
0
1
\$\begingroup\$

Defining natural numbers

The following message:

"número natural(0,1,2,...) entre 1 e 1000"

both defines natural numbers in general and identifies which specific natural numbers are relevant here. I wouldn't do that first part; it's a little confusing since you're both saying and not saying that 0 is okay (even though it obviously isn't okay after a little thought). "número natural entre 1 e 1000" is clearer; if you're worried that people won't know what a natural number is, you could choose simpler vocabulary that doesn't need clarification at all.

Collection semantics

It's minor, but I don't think a list here makes much sense:

if opcao_calc.strip().lower() in ["não", "nao"]:

A set (since you're looking for containment) or a tuple (since the pair is immutable) both seem more semantically accurate to me.

Multiple welcomes

You only need to welcome the user when they first start the program; multiple welcome messages might be a little confusing and certainly occupy more screen space than necessary.

def menu():
    print("Bem-vindo(a)!")
    while True:
        print("O que deseja fazer?")
        ...

Menu option conversions

Since you're not doing any math with opcao_menu, you don't need to convert it to a float at all.

opcao_menu = input("digite 1, 2 ou 3: ")
if opcao_menu == "1": ...
elif opcao_menu == "2": ...
elif opcao_menu == "3": ...
elif opcao_menu == "3.14": ...
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.