Juego de consola Python simple con flujo de código ineficiente

Oct 07 2020

Hice un programa simple como ejercicio para mejorar el flujo de mi código en Python, que hace lo siguiente:

  1. pide al usuario que ingrese su nombre
  2. les presenta la opción de imprimir su nombre al revés o imprimir el número de caracteres
  3. una vez impresa la salida, se le pregunta al usuario si desea "volver a jugar". si no, sale

¿He hecho algo especialmente tonto? ¿Alguna fruta madura? ¿Mejores prácticas que desconozco?

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

Respuestas

31 AryanParekh Oct 07 2020 at 10:55

Intente olvidar todo lo que sabe sobre el código y asuma que no es el autor. Imagínese que es una tercera persona que lee el código, no sabe nada al respecto y lo lee por primera vez.

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

Muy bien, userinput()debo tomar alguna entrada y ponerla en ui. Tiene sentido, pero ¿qué es choosef()?.

Convenio de denominación

Utilice nombres significativos para funciones y variables. toma este ejemplo

x = 3.14
y = 24

que es xy ypara el lector? ¿Es ese el precio de algo?

pi_value = 3.14
number_of_hours = 24

Ahhh está bien, ahora sé exactamente lo que 3.14significa. Entonces, si lo uso en algún lugar, el lector también sabrá a qué me refiero exactamente. Esta es una parte importante de la escritura de código limpio.

Otro aspecto es el estilo. Hay algunas formas en que puedo escribir la entrada del usuario *

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

¿A cuál debo seguir?

Para tener una convención de nomenclatura coherente, el código de Python sigue la convención de nomenclatura PEP-8 . Cuando digo lo siguiente, quiero decir que se recomienda que también lo siga, ya que otras bibliotecas de Python también lo usan. Hace que el código se vea más limpio.

A continuación, cosas como funciones: lower_snake_case

Siguen las clases: CamelCase

Puede leer el enlace para obtener más información.

Tomando entrada en Python

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

Claramente, desea mostrar un mensaje al usuario antes de que ingrese algo. Es por eso que la input()función tiene algo llamado solicitud de entrada .

name = input("Enter your name: ")

Puede mostrar el mensaje entre (). Esto elimina la línea adicional. También tenga en cuenta que cambié na namepor las razones que mencioné anteriormente.

Formateo de cadenas

De su código, puedo ver que concatenó cadenas con +para formar oraciones significativas. Eso funciona, pero hay un gran problema cuando desea utilizar variables de diferentes tipos.

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

TypeError: solo puede concatenar str (no "int") a str

Simplemente use las cadenas f de Python 3 . Coloque la letra 'f' antes"

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

Limpiador.

valor de retorno de userinput()

Lo que está haciendo actualmente es devolver una tupla de choicey name. Es mejor que los mantenga como están porque más adelante, los corta solo para obtenerlos nuevamente. Esto significa que lo haces directamente

return name, choice

# Calling the function


name, choice = userinput()

Estructura de código

Un par de puntos

  • No preguntes "Do you want to play again? "en la play_again()función. La razón por la que llamó a esa función debería ser porque el usuario quiere volver a jugar. Mueva eso a una playgame()función que llamará user_input()cada vez que el usuario quiera jugar el juego, y salga del bucle solo si el usuario ingresa 'n'o"no"

  • spaces = spaces + 1 se puede simplificar en spaces += 1

  • Mueva la parte donde cuenta el número de caracteres a una función separada que devolverá un número entero. Por lo que su play_game()función no hace otra cosa que jugar . Cuando necesite los personajes number_of_char = character_len( name ),.

  • Use enum para mayor claridad.

Una versión mejorada del 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: también he agregado print(chr(27) + "[2J")para borrar la pantalla.

3 AmanDesai Oct 07 2020 at 06:26

Puedes tener una mejor estructura. Aquí hay una explicación detallada. Errores de flujo de datos que no debe hacer en el mundo real:

  • Aquí, sus llamadas a funciones no tienen sentido. Siempre que defina y use funciones, defínelas de tal manera que no se llamen entre sí, es decir, debería haber una estructura de árbol. La función principal controlará todo. (Consulte el código a continuación para echar un vistazo).
  • Tu guión puede tener una mejor estructura. Consulte el código a continuación.

*** PROTIP: Si quieres que tu código sea más fácil de mantener, divídelo en módulos y colócalos en diferentes archivos e impórtalos ***

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

Creo que la estructura es bastante complicada, con llamadas a input () y choosef () dispersas en múltiples lugares / niveles, por lo que el programa no es súper legible ni escalable (si tuviera que manejar más entradas de usuario).

Un enfoque más legible sería un bucle principal como, en pseudocó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

También en Python hay una forma más corta de invertir una cadena con sintaxis de corte: "abc" [:: - 1]

1 Noname Oct 07 2020 at 06:39

Hay dos áreas en las que su código podría mejorar aún más.

Primero, puede ejecutar herramientas como flake8 o pylint para verificar su código en busca de 'violaciones' de PEP8. PEP8 es una guía de estilo de Python que se acepta como estilo de facto para el código Python. No me centraré en esto, ya que se trata principalmente de un proceso automático y una elección algo personal.

En segundo lugar, puede realizar algunas mejoras en su código con respecto a la denominación y la documentación. Esto es lo que llamamos legibilidad de su código. Yo mismo he probado esto y esto es lo que (personalmente) encuentro que es un mejor código.

Una cosa que puede mejorar es eliminar toda la magia de su código. En las dos líneas a continuación, establece una variable uiy luego pasa el primer y segundo elemento a otra función. Si veo estas dos líneas, no tengo idea de lo que estás haciendo.

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

Esto se puede simplificar y hacer más legible seleccionando mejores nombres de variable y (en este caso al menos) usando el desempaquetado de tuplas:

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

El ejemplo anterior se puede aplicar a todo su código. Siempre juzgo mi código (y el código que reviso) con la pregunta: "Si le muestro este bloque de código a alguien, ¿la intención del código es clara para la persona que lo lee, sin requerir conocimiento de todo el programa?"