Estoy tratando de modificar un programa que juega el juego 'Piedra, papel, tijera', para que observe la validación de datos. Este objetivo aquí es que la validación se realiza asegurando que la entrada del usuario sea igual a 'piedra', 'papel' o 'tijera', antes de userMove return

A continuación se muestra una función, que creé para la entrada del usuario donde he usado un while not in para validar la entrada del usuario y return una entrada válida o print una cadena, solicitando una entrada válida .

Pregunta: ¿es esta la forma más efectiva de validar en esta instancia? ¿Quizás usar la función ValueError es más efectivo?

def userMove():
    usersMove = input("Time to make your choice: ")
    while usersMove not in ['rock', 'paper', 'scissors']:
        print("That is not a valid")
        usersMove = input("Time to make your choice: ")
    return usersMove
3
William 31 oct. 2017 a las 00:37

3 respuestas

La mejor respuesta

Una cosa que podría hacer es usar un conjunto ya que las búsquedas son más rápidas en conjuntos que en la lista, también como dice un comentario, usando .lower() haría su código más robusto:

def userMove():
    usersMove = input("Time to make your choice: ")
    while usersMove.lower() not in {'rock', 'paper', 'scissors'}:
        print("That is not a valid")
        usersMove = input("Time to make your choice: ")
    return usersMove

EDITAR

Además, como señaló @utengr, utilizando mis recomendaciones anteriores, también podría transformar su código de esta manera,

def userMove():
    while True:
        usersMove = input("Time to make your choice: ")
        if usersMove.lower() in {'rock', 'paper', 'scissors'}:
            return usersMove
        print("That is not a valid")

Tenga en cuenta que su pregunta era sobre el rendimiento. El uso de la segunda solución no afectará el rendimiento de ninguna manera, la ganancia principal aquí es con respecto a la legibilidad ya que compacta el código en un bloque.

4
scharette 30 oct. 2017 a las 22:18

La diferencia entre set.__contains__ y list.__contains__ es de unos pocos nanosegundos en el mejor de los casos. ¡Pero la diferencia en la velocidad de entrada del usuario se mide en milisegundos o más! Entonces, lo más efectivo es dejar que el usuario ingrese una sola letra.

def fast_user_move():
    while True:
        usersMove = input("Time to make your choice: ").lower().strip()
        if usersMove and usersMove[0] in 'rps':
            return usersMove[0]
        print("That is not a valid choice")

Para una solución súper efectiva, use la readchar, y el usuario solo tiene que presionar una sola ¡ tecla de retorno no necesaria!

from readchar import readchar

def super_fast_user_move():
    print('Time to make your choice: [r]ock, [p]aper or [s]cissors?')
    while True:
        choice = readchar().lower()
        if choice in 'rps':
            return choice
        print(f'{choice} is not a valid choice')

Editar : ¡Esta velocidad increíble tiene un costo! Si el usuario intenta ingresar STOP , la entrada se interpretará como Tijera , lo que podría conducir a todo tipo de peligro. Gracias a @scharette por la advertencia.

Editar 2 : Aquí hay algunos puntos de referencia que hice. Como puede ver, esta versión es casi 200 veces más rápida que la original, medida en tiempo de pared.

In [12]: %time userMove()
Time to make your choice: scissor
That is not a valid
Time to make your choice: scissors
CPU times: user 1e+03 µs, sys: 1 ms, total: 2 ms
Wall time: 6.02 s
Out[12]: 'scissors'


In [13]: %time super_fast_user_move()
Time to make your choice: [r]ock, [p]aper or [s]cissors?
CPU times: user 1 ms, sys: 0 ns, total: 1 ms
Wall time: 34.6 ms
Out[13]: 's'

(Pero debe tenerse en cuenta que escribí mal las "tijeras" una vez).

2
Håken Lid 30 oct. 2017 a las 22:59

Debe usar conjuntos para las comprobaciones de membresía, ya que son más rápidos que las listas. Además, se prefiere while true sobre un while some condition [Documentos de Python].

def userMove():
    while True:
        usersMove = input("Time to make your choice: ")
        if usersMove in {'rock', 'paper', 'scissors'}:
            return usersMove
        print("That is not a valid")

También puede agregarle usersMove.lower() si no desea que se distinga entre mayúsculas y minúsculas como lo sugieren @scharette y @yklsga.

3
utengr 30 oct. 2017 a las 21:52