Jogo de console Python simples com fluxo de código ineficiente

Oct 07 2020

Fiz um programa simples como um exercício para melhorar meu fluxo de código em Python, que faz o seguinte:

  1. pede ao usuário para inserir seu nome
  2. apresenta a eles a opção de imprimir seu nome ao contrário ou imprimir o número de caracteres
  3. depois que a saída é impressa, o usuário é questionado se deseja "jogar novamente". se não, sai

Fiz algo especialmente estúpido? Alguma fruta baixa? Melhor prática que desconheço?

from sys import exit

def userinput():
    print('Enter your name:')
    n = input()
    print('Hello, ' + n + ', would you rather (R)everse or (C)ount the letters of your name?')
    a = input()
    return (a,n)

def choosef(choice,myname):
    while choice not in ['R','C']:
        print("Only 'R' or 'C' are valid. Try again:")
        choice = input()
    if choice == 'R':
        print(''.join(reversed(myname)))
    else:
        spaces = 0
        for c in list(myname):
            if c == ' ':
                spaces = spaces + 1
        print('Total # Characters: ' + str(len(myname) - spaces))
    playagain()

def playagain():
    print("Would you like to play again, (Y)es or any other character to exit?")
    yn = input()
    if yn == 'Y':
        ui = userinput()
        choosef(ui[0],ui[1])
    else:
        exit()

ui = userinput()
choosef(ui[0],ui[1])

Respostas

31 AryanParekh Oct 07 2020 at 10:55

Tente esquecer tudo o que você sabe sobre o código e suponha que você não seja o autor. Imagine-se como uma terceira pessoa lendo o código, ela não sabe nada sobre ele e apenas o lê pela primeira vez.

ui = userinput()
choosef(ui[0],ui[1])

Tudo bem, userinput()deve pegar algumas informações e colocá-las em ui. Faz sentido, mas o que é choosef()?

Convenção de nomes

Use nomes significativos para funções e variáveis. veja este exemplo

x = 3.14
y = 24

o que é xe ypara o leitor? Esse é o preço de alguma coisa?

pi_value = 3.14
number_of_hours = 24

Ahhh ok, agora eu sei exatamente o que 3.14significa. Portanto, se eu usá-lo em algum lugar, o leitor também saberá o que quero dizer exatamente. Esta é uma parte importante da escrita de código limpo.

Outro aspecto é o estilo. Existem algumas maneiras de escrever a entrada do usuário *

user_input()
USERINPUT()
UserInput()
userinput()

Qual devo seguir?

Para ter uma convenção de nomenclatura consistente, o código python segue a convenção de nomenclatura PEP-8 . Quando digo segue, quero dizer que é recomendável que você também siga, pois outras bibliotecas Python também usam isso. Isso faz com que o código pareça mais limpo.

Seguem coisas como funções: lower_snake_case

Seguem as aulas: CamelCase

Você pode ler o link para mais informações.

Recebendo entrada em Python

print('Enter your name:')
n = input()

Obviamente, você deseja exibir uma mensagem ao usuário antes que ele insira algo. É por isso que a input()função tem algo chamado prompt de entrada .

name = input("Enter your name: ")

Você pode exibir a mensagem entre os (). Isso remove a linha adicional. Observe também que mudei npara namepelos motivos que mencionei acima.

Formatando strings

Pelo seu código, posso ver que você concatenou strings com +para formar frases significativas. Isso funciona, mas há um grande problema quando você deseja usar variáveis ​​de tipos diferentes.

name = "Eric"
age = 14
job = "Comedian"
print("Hello " + name  + "You are " + age + " years old and you are a " + comedian)

TypeError: só pode concatenar str (não "int") para str

Basta usar as strings f do Python 3 . Coloque a letra 'f' antes"

print(f"Hello {name}, you are {age} years old ")

Limpador.

valor de retorno de userinput()

O que você está fazendo atualmente é retornar uma tupla de choicee name. É melhor mantê-los como estão porque, mais tarde, você corta apenas para obtê-los novamente. Isso significa que você faz diretamente

return name, choice

# Calling the function


name, choice = userinput()

Estrutura de código

Alguns pontos

  • Não pergunte "Do you want to play again? "na play_again()função. A razão pela qual você chamou essa função deve ser porque o usuário deseja jogar novamente. Mova isso para uma playgame()função que chamará user_input()toda vez que o usuário quiser jogar o jogo e interrompa o loop apenas se o usuário inserir 'n'ou"no"

  • spaces = spaces + 1 pode ser simplificado em spaces += 1

  • Mova a parte onde você conta o número de caracteres em uma função separada que retornará um inteiro. Portanto, sua play_game()função não faz nada além de jogar o jogo . Quando você precisar dos personagens number_of_char = character_len( name ),.

  • Use enum para maior clareza.

Uma versão melhorada do código

from enum import Enum

class PrintChoices(Enum):
    number_of_char = 'c'
    reversed_name = 'r'
    exit_choice = 'e'


def find_num_of_char(name):
    return len(name) - name.count(' ') 

def reverse_name(name):
    return name[::-1]

def user_input():
    name = input("Enter your name: " )
    choice = input("Would you like to (r)everse your name\n or would you like to print the number of (c)haracters or (e)xit?: ")
    return name, choice

def clear_screen():
    print(chr(27) + "[2J")

def play_game():
    while True:
        clear_screen()
        name, choice = user_input()
        if choice == PrintChoices.reversed_name.value:
            print(reverse_name(name))
            input("Press any key to continue...")
        elif choice == PrintChoices.number_of_char.value:
            print(find_num_of_char(name))
            input("Press any key to continue...")
        elif choice == PrintChoices.exit_choice.value:
            break
        else:
            input("Invalid input, Press any key to continue...")



play_game()

Nota: Eu também adicionei print(chr(27) + "[2J")para limpar a tela.

3 AmanDesai Oct 07 2020 at 06:26

Você pode ter uma estrutura melhor. Aqui está uma explicação detalhada. Erros de fluxo de dados que você não deve fazer no mundo real:

  • Aqui, suas chamadas de função não fazem sentido. Sempre que você definir e usar funções, defina-as de forma que não chamem umas às outras, ou seja, deve haver uma estrutura em árvore. A função principal controlará tudo. (Veja o código abaixo para ter uma ideia.)
  • Seu script pode ter uma estrutura melhor. Veja o código abaixo.

*** PROTIP: Se você quiser tornar seu código mais sustentável, divida-o em módulos e coloque todos eles em arquivos diferentes e importe-os ***

def take_name_input():
    print('Enter your name:')
    n = input()
    return n

def ask_choice():
   print('Hello, ' + n + ', would you rather (R)everse or (C)ount the letters of your name?')
    a = input()
    return a

def playgame(myname):
    while True:
        choice = ask_choice()
        if choice == 'R':
            print(''.join(reversed(myname)))
        elif choice == 'C':
            for c in list(myname):
                if c == ' ':
                    spaces = spaces + 1
            print('Total # Characters: ' + str(len(myname) - spaces))
        else:
            break

name = take_name_input()
playgame(name)
3 Noname Oct 07 2020 at 06:37

Acho que a estrutura é bastante complicada, com chamadas para input () e choosef () espalhadas em vários locais / níveis, portanto, o programa não é super legível e não escalonável (se você tivesse que lidar com mais entradas do usuário).

Uma abordagem mais legível seria um loop principal como - em pseudo código

while True:
  Get user input from 3 choices R / C / E(xit)
  if input = E:
     exit
  else if input = R:
     handle R case
  else 
     handle C case

Também em python, há uma maneira mais curta de reverter uma string com sintaxe de fatiamento: "abc" [:: - 1]

1 Noname Oct 07 2020 at 06:39

Existem duas áreas em que seu código pode melhorar ainda mais.

Primeiro, você pode executar ferramentas como flake8 ou pylint para verificar se há 'violações' do PEP8 em seu código. PEP8 é um guia de estilo Python que é aceito como o estilo de fato para o código Python. Não vou me concentrar nisso, pois se trata principalmente de um processo automático e uma escolha um tanto pessoal.

Em segundo lugar, você pode fazer algumas melhorias em seu código com relação à nomenclatura e documentação. Isso é o que chamamos de legibilidade do seu código. Eu tentei fazer isso sozinho e é o que eu (pessoalmente) considero um código melhor.

Uma coisa que você pode melhorar é remover toda a magia do seu código. Nas duas linhas abaixo, você define uma variável uie, a seguir, passa o primeiro e o segundo elemento para outra função. Se eu vir essas duas linhas, não tenho ideia do que você está fazendo.

ui = userinput()
choosef(ui[0],ui[1])

Isso pode ser simplificado e mais legível selecionando nomes de variáveis ​​melhores e (neste caso, pelo menos) usando descompactação de tupla:

action, name = get_user_input()
handle_user_action(action, name)

O exemplo acima pode ser aplicado em todo o seu código. Sempre julgo meu código (e o código que reviso) com a pergunta: "Se eu mostrar este bloco de código a alguém, a intenção do código é clara para a pessoa que o lê, sem exigir conhecimento de todo o programa?"