Semplice gioco per console Python con flusso di codice inefficiente

Oct 07 2020

Ho creato un semplice programma come esercizio per migliorare il flusso del mio codice in Python, che fa quanto segue:

  1. chiede all'utente di inserire il proprio nome
  2. presenta loro la possibilità di stampare il loro nome al contrario o stampare il numero di caratteri
  3. dopo che l'output è stato stampato, all'utente viene chiesto se desidera "riprodurre di nuovo". in caso contrario, esce

Ho fatto qualcosa di particolarmente stupido? Qualche frutto basso? Best practice di cui non sono a conoscenza?

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

Risposte

31 AryanParekh Oct 07 2020 at 10:55

Cerca di dimenticare tutto ciò che sai sul codice e presumi di non essere l'autore. Immagina di essere una terza persona che legge il codice, non ne sa nulla e lo legge per la prima volta.

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

Va bene, userinput()devo prendere un input e inserirlo ui. Ha senso, ma cos'è choosef()?

Convenzione di denominazione

Usa nomi significativi per funzioni e variabili. prendi questo esempio

x = 3.14
y = 24

cos'è xe yper il lettore? È questo il prezzo di qualcosa?

pi_value = 3.14
number_of_hours = 24

Ahhh okay, ora so esattamente cosa 3.14significa. Quindi, se lo uso da qualche parte, il lettore saprà anche cosa intendo esattamente. Questa è una parte importante della scrittura di codice pulito.

Un altro aspetto è lo stile. Ci sono alcuni modi in cui posso scrivere l'input dell'utente *

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

Quale dovrei seguire?

Per avere una convenzione di denominazione coerente, il codice python segue la convenzione di denominazione PEP-8 . Quando dico segue, intendo che è consigliabile seguirlo anche tu poiché anche altre librerie python lo usano. Rende il codice più pulito.

Cose come le funzioni seguono: lower_snake_case

Seguono le classi: CamelCase

Puoi leggere il link per maggiori informazioni.

Prendere input in Python

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

Chiaramente, vuoi mostrare un messaggio all'utente prima che inserisca qualcosa. Questo è il motivo per cui la input()funzione ha qualcosa chiamato prompt di input .

name = input("Enter your name: ")

È possibile visualizzare il messaggio tra i file (). Questo rimuove la linea aggiuntiva. Si noti inoltre che sono passato na nameper i motivi sopra menzionati.

Formattazione delle stringhe

Dal tuo codice, posso vedere che hai concatenato stringhe con +per formare frasi significative. Funziona, ma c'è un grosso problema quando vuoi usare variabili di diversi tipi.

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

TypeError: può solo concatenare str (non "int") a str

Usa semplicemente le stringhe f di Python 3 . Metti la lettera "f" prima"

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

Cleaner.

valore restituito da userinput()

Quello che stai facendo attualmente è restituire una tupla di choicee name. È meglio che tu li tenga così come sono perché in seguito, li tagli solo per riprenderli. Ciò significa che lo fai direttamente

return name, choice

# Calling the function


name, choice = userinput()

Struttura del codice

Un paio di punti

  • Non chiedere "Do you want to play again? "nella play_again()funzione. Il motivo per cui hai chiamato quella funzione dovrebbe essere perché l'utente vuole giocare di nuovo. Spostalo in una playgame()funzione che chiamerà user_input()ogni volta che l'utente vuole giocare e interrompi il ciclo solo se l'utente entra 'n'o"no"

  • spaces = spaces + 1 può essere semplificato in spaces += 1

  • Spostare la parte in cui si conta il numero di caratteri in una funzione separata che restituirà un numero intero. Quindi la tua play_game()funzione non fa altro che giocare . Quando hai bisogno dei personaggi number_of_char = character_len( name ),.

  • Usa enum per chiarezza.

Una versione migliorata del codice

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: ho anche aggiunto print(chr(27) + "[2J")per cancellare lo schermo.

3 AmanDesai Oct 07 2020 at 06:26

Puoi avere una struttura migliore. Ecco una spiegazione dettagliata. Errori del flusso di dati che non dovresti fare nel mondo reale:

  • Qui, le tue chiamate di funzione non hanno senso. Ogni volta che si definiscono e si utilizzano le funzioni, definirle in modo tale che non si chiamino tra loro, ovvero dovrebbe esserci una struttura ad albero. La funzione principale controllerà tutto. (Vedi sotto il codice per dare un'occhiata.)
  • Il tuo script può avere una struttura migliore. Vedi sotto il codice.

*** PROTIP: Se vuoi rendere il tuo codice più manutenibile, suddividilo in moduli e mettili tutti in file diversi e importali ***

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

Penso che la struttura sia abbastanza contorta, con chiamate a input () e choosef () sparse in più punti / livelli, quindi il programma non è super leggibile e non scalabile (se dovessi gestire più input dell'utente).

Un approccio più leggibile sarebbe un ciclo principale come - nello pseudo codice

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

Anche in Python c'è un modo più breve per invertire una stringa con la sintassi di slicing: "abc" [:: - 1]

1 Noname Oct 07 2020 at 06:39

Ci sono due aree in cui il tuo codice potrebbe migliorare ulteriormente.

Per prima cosa puoi eseguire strumenti come flake8 o pylint per controllare il tuo codice per 'violazioni' di PEP8. PEP8 è una guida allo stile Python che è accettata come lo stile di fatto per il codice Python. Non mi concentrerò su questo dato che questo è principalmente un processo automatico e una scelta in qualche modo personale.

In secondo luogo puoi apportare alcuni miglioramenti al tuo codice per quanto riguarda la denominazione e la documentazione. Questo è ciò che chiamiamo leggibilità del tuo codice. Ho provato io stesso a questo e questo è ciò che (personalmente) trovo essere un codice migliore.

Una cosa che puoi migliorare è rimuovere tutta la magia dal tuo codice. Nelle due righe sottostanti si imposta una variabile uie quindi si passa il primo e il secondo elemento a un'altra funzione. Se vedo queste due righe, non ho idea di cosa stai facendo.

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

Questo può essere semplificato e reso più leggibile selezionando nomi di variabili migliori e (in questo caso almeno) utilizzando lo spacchettamento della tupla:

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

L'esempio sopra può essere applicato a tutto il codice. Giudico sempre il mio codice (e il codice che rivedo) con la domanda: "Se mostro questo blocco di codice a qualcuno, l'intenzione del codice è chiara a chi lo legge, senza richiedere la conoscenza dell'intero programma?"