Línea de comandos APT como entrada de interfaz sí / no?

169

¿Hay alguna forma corta de lograr lo que hace la interfaz de línea de comandos APT ( Advanced Package Tool ) en Python?

Quiero decir, cuando el administrador de paquetes pregunta una pregunta de sí / no seguida de [Yes/no], el guión acepta YES/Y/yes/yo Enter(por defecto, Yescomo lo indica la letra mayúscula).

Lo único que encuentro en los documentos oficiales es inputy raw_input...

Sé que no es tan difícil emular, pero es molesto reescribir: |

h3.
fuente
15
En Python 3, raw_input()se llama input().
Tobu

Respuestas:

222

Como mencionó, la forma más fácil es usar raw_input()(o simplemente input()para Python 3 ). No hay una forma integrada de hacer esto. De la receta 577058 :

import sys

def query_yes_no(question, default="yes"):
    """Ask a yes/no question via raw_input() and return their answer.

    "question" is a string that is presented to the user.
    "default" is the presumed answer if the user just hits <Enter>.
        It must be "yes" (the default), "no" or None (meaning
        an answer is required of the user).

    The "answer" return value is True for "yes" or False for "no".
    """
    valid = {"yes": True, "y": True, "ye": True,
             "no": False, "n": False}
    if default is None:
        prompt = " [y/n] "
    elif default == "yes":
        prompt = " [Y/n] "
    elif default == "no":
        prompt = " [y/N] "
    else:
        raise ValueError("invalid default answer: '%s'" % default)

    while True:
        sys.stdout.write(question + prompt)
        choice = raw_input().lower()
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            sys.stdout.write("Please respond with 'yes' or 'no' "
                             "(or 'y' or 'n').\n")

Ejemplo de uso:

>>> query_yes_no("Is cabbage yummier than cauliflower?")
Is cabbage yummier than cauliflower? [Y/n] oops
Please respond with 'yes' or 'no' (or 'y' or 'n').
Is cabbage yummier than cauliflower? [Y/n] [ENTER]
>>> True

>>> query_yes_no("Is cabbage yummier than cauliflower?", None)
Is cabbage yummier than cauliflower? [y/n] [ENTER]
Please respond with 'yes' or 'no' (or 'y' or 'n').
Is cabbage yummier than cauliflower? [y/n] y
>>> True
fmark
fuente
elif choice in valid:Y probablemente devolvería un booleano.
Ignacio Vazquez-Abrams
Buena elección Ignacio, rectificando
fmark
24
En realidad, hay una función strtobool en la biblioteca estándar: docs.python.org/2/distutils/…
Alexander Artemenko
14
Solo un recuerdo: raw_input()se llama input()en Python3
nachouve
De hecho super útil! Simplemente reemplace raw_input()con input()para Python3.
Muhammad Haseeb
93

Lo haría de esta manera:

# raw_input returns the empty string for "enter"
yes = {'yes','y', 'ye', ''}
no = {'no','n'}

choice = raw_input().lower()
if choice in yes:
   return True
elif choice in no:
   return False
else:
   sys.stdout.write("Please respond with 'yes' or 'no'")
Vicki Laidler
fuente
8
raw_input()se llama input()en Python3
gizzmole
49

Hay una función strtoboolen la biblioteca estándar de Python: http://docs.python.org/2/distutils/apiref.html?highlight=distutils.util#distutils.util.strtobool

Puede usarlo para verificar la entrada del usuario y transformarla Trueo Falsevalor.

Alexander Artemenko
fuente
fprobablemente significa Falso y False == 0, por lo tanto, entiendo la lógica. Sin embargo, por qué la función devolvería un en intlugar de un booles un misterio para mí.
François Leblanc
@ FrançoisLeblanc en cuanto a por qué es más común en las bases de datos. Si no es explícitamente Falseo 0(Cero). Cualquier cosa, de lo que se evalúa usando la función bool se convierte en verdadera y volverá: 1.
JayRizzo
@ JayRizzo Lo entiendo, y ambos son funcionalmente similares en la mayoría de los aspectos. Pero significa que no puede usar la comparación de singleton, es decir if strtobool(string) is False: do_stuff().
François Leblanc
48

Una manera muy simple (pero no muy sofisticada) de hacer esto por una sola opción sería:

msg = 'Shall I?'
shall = input("%s (y/N) " % msg).lower() == 'y'

También podría escribir una función simple (ligeramente mejorada) alrededor de esto:

def yn_choice(message, default='y'):
    choices = 'Y/n' if default.lower() in ('y', 'yes') else 'y/N'
    choice = input("%s (%s) " % (message, choices))
    values = ('y', 'yes', '') if choices == 'Y/n' else ('y', 'yes')
    return choice.strip().lower() in values

Nota: En Python 2, use en raw_inputlugar de input.

Danilo Bargen
fuente
77
Me encanta el primer acercamiento. Corto y fácil. Usé algo comoresult = raw_input("message").lower() in ('y','yes')
Adrian Shum
47

Puede usar el método de clicconfirm .

import click

if click.confirm('Do you want to continue?', default=True):
    print('Do something')

Esto imprimirá:

$ Do you want to continue? [Y/n]:

Debería funcionar para Python 2/3Linux, Mac o Windows.

Documentos: http://click.pocoo.org/5/prompts/#confirmation-prompts

Eyal Levin
fuente
24

como lo mencionó @Alexander Artemenko, aquí hay una solución simple usando strtobool

from distutils.util import strtobool

def user_yes_no_query(question):
    sys.stdout.write('%s [y/n]\n' % question)
    while True:
        try:
            return strtobool(raw_input().lower())
        except ValueError:
            sys.stdout.write('Please respond with \'y\' or \'n\'.\n')

#usage

>>> user_yes_no_query('Do you like cheese?')
Do you like cheese? [y/n]
Only on tuesdays
Please respond with 'y' or 'n'.
ok
Please respond with 'y' or 'n'.
y
>>> True
James
fuente
8
solo curiosidad ... ¿por qué en sys.stdout.writelugar de print?
Anentropic
2
Tenga en cuenta que strtobool()no requiere (de mis pruebas) a lower(). Sin embargo, esto no es explícito en su documentación.
Michael - ¿Dónde está Clay Shirky el
15

Sé que esto se ha respondido de muchas maneras y esto puede no responder la pregunta específica de OP (con la lista de criterios), pero esto es lo que hice para el caso de uso más común y es mucho más simple que las otras respuestas:

answer = input('Please indicate approval: [y/n]')
if not answer or answer[0].lower() != 'y':
    print('You did not indicate approval')
    exit(1)
Douglas Adams
fuente
esto no funciona con python 2 - raw_inputfue renombrado inputen python 3 stackoverflow.com/questions/21122540/…
Brian Tingle
9

También puedes usar el apuntador .

Descaradamente tomado del archivo Léame:

#pip install prompter

from prompter import yesno

>>> yesno('Really?')
Really? [Y/n]
True

>>> yesno('Really?')
Really? [Y/n] no
False

>>> yesno('Really?', default='no')
Really? [y/N]
True
ibizaman
fuente
44
Tenga en cuenta que el comportamiento del apuntador es bastante inverso cuando lo está usando con "default = 'no'"; devolverá Verdadero cuando elija 'no' y Falso cuando elija 'sí'.
rem
7

Modifiqué la respuesta de fmark a python 2/3 compatible más pythonic.

Vea el módulo de utilidad de ipython si está interesado en algo con más manejo de errores

# PY2/3 compatibility
from __future__ import print_function
# You could use the six package for this
try:
    input_ = raw_input
except NameError:
    input_ = input

def query_yes_no(question, default=True):
    """Ask a yes/no question via standard input and return the answer.

    If invalid input is given, the user will be asked until
    they acutally give valid input.

    Args:
        question(str):
            A question that is presented to the user.
        default(bool|None):
            The default value when enter is pressed with no value.
            When None, there is no default value and the query
            will loop.
    Returns:
        A bool indicating whether user has entered yes or no.

    Side Effects:
        Blocks program execution until valid input(y/n) is given.
    """
    yes_list = ["yes", "y"]
    no_list = ["no", "n"]

    default_dict = {  # default => prompt default string
        None: "[y/n]",
        True: "[Y/n]",
        False: "[y/N]",
    }

    default_str = default_dict[default]
    prompt_str = "%s %s " % (question, default_str)

    while True:
        choice = input_(prompt_str).lower()

        if not choice and default is not None:
            return default
        if choice in yes_list:
            return True
        if choice in no_list:
            return False

        notification_str = "Please respond with 'y' or 'n'"
        print(notification_str)
Bryce Guinta
fuente
Compatible con Python 2 y 3, muy legible. Terminé usando esta respuesta.
François Leblanc
4

en 2.7, ¿esto es demasiado no pitónico?

if raw_input('your prompt').lower()[0]=='y':
   your code here
else:
   alternate code here

captura cualquier variación de Sí al menos.

Speqtre
fuente
4

Haciendo lo mismo con python 3.x, donde raw_input()no existe:

def ask(question, default = None):
    hasDefault = default is not None
    prompt = (question 
               + " [" + ["y", "Y"][hasDefault and default] + "/" 
               + ["n", "N"][hasDefault and not default] + "] ")

    while True:
        sys.stdout.write(prompt)
        choice = input().strip().lower()
        if choice == '':
            if default is not None:
                return default
        else:
            if "yes".startswith(choice):
                return True
            if "no".startswith(choice):
                return False

        sys.stdout.write("Please respond with 'yes' or 'no' "
                             "(or 'y' or 'n').\n")
pjm
fuente
No, esto no funciona. En más de una forma en realidad. Actualmente estoy tratando de solucionarlo, pero creo que esto se parecerá mucho a la respuesta aceptada una vez que haya terminado.
Gormador el
Te edité anwser @pjm. Por favor considere revisarlo :-)
Gormador
3

Para Python 3, estoy usando esta función:

def user_prompt(question: str) -> bool:
    """ Prompt the yes/no-*question* to the user. """
    from distutils.util import strtobool

    while True:
        user_input = input(question + " [y/n]: ").lower()
        try:
            result = strtobool(user_input)
            return result
        except ValueError:
            print("Please use y/n or yes/no.\n")

La función strtobool convierte una cadena en bool. Si la cadena no se puede analizar, generará un ValueError.

En Python 3, raw_input ha sido renombrado como input .

SuperKeksmann
fuente
2

Puede probar algo como el siguiente código para poder trabajar con las opciones de la variable 'aceptado' que se muestra aquí:

print( 'accepted: {}'.format(accepted) )
# accepted: {'yes': ['', 'Yes', 'yes', 'YES', 'y', 'Y'], 'no': ['No', 'no', 'NO', 'n', 'N']}

Aquí está el código ...

#!/usr/bin/python3

def makeChoi(yeh, neh):
    accept = {}
    # for w in words:
    accept['yes'] = [ '', yeh, yeh.lower(), yeh.upper(), yeh.lower()[0], yeh.upper()[0] ]
    accept['no'] = [ neh, neh.lower(), neh.upper(), neh.lower()[0], neh.upper()[0] ]
    return accept

accepted = makeChoi('Yes', 'No')

def doYeh():
    print('Yeh! Let\'s do it.')

def doNeh():
    print('Neh! Let\'s not do it.')

choi = None
while not choi:
    choi = input( 'Please choose: Y/n? ' )
    if choi in accepted['yes']:
        choi = True
        doYeh()
    elif choi in accepted['no']:
        choi = True
        doNeh()
    else:
        print('Your choice was "{}". Please use an accepted input value ..'.format(choi))
        print( accepted )
        choi = None
Randy Skretka
fuente
2

Como novato en programación, encontré un montón de respuestas anteriores demasiado complejas, especialmente si el objetivo es tener una función simple a la que pueda pasar varias preguntas de sí / no, obligando al usuario a seleccionar sí o no. Después de recorrer esta página y varias otras, y tomar prestadas todas las buenas ideas, terminé con lo siguiente:

def yes_no(question_to_be_answered):
    while True:
        choice = input(question_to_be_answered).lower()
        if choice[:1] == 'y': 
            return True
        elif choice[:1] == 'n':
            return False
        else:
            print("Please respond with 'Yes' or 'No'\n")

#See it in Practice below 

musical_taste = yes_no('Do you like Pine Coladas?')
if musical_taste == True:
    print('and getting caught in the rain')
elif musical_taste == False:
    print('You clearly have no taste in music')
Miguel
fuente
1
¿No debería llamarse al argumento "pregunta" en lugar de "respuesta"?
AFP_555
1

Qué tal esto:

def yes(prompt = 'Please enter Yes/No: '):
while True:
    try:
        i = raw_input(prompt)
    except KeyboardInterrupt:
        return False
    if i.lower() in ('yes','y'): return True
    elif i.lower() in ('no','n'): return False
Visgean Skeloru
fuente
1

Esto es lo que uso:

import sys

# cs = case sensitive
# ys = whatever you want to be "yes" - string or tuple of strings

#  prompt('promptString') == 1:               # only y
#  prompt('promptString',cs = 0) == 1:        # y or Y
#  prompt('promptString','Yes') == 1:         # only Yes
#  prompt('promptString',('y','yes')) == 1:   # only y or yes
#  prompt('promptString',('Y','Yes')) == 1:   # only Y or Yes
#  prompt('promptString',('y','yes'),0) == 1: # Yes, YES, yes, y, Y etc.

def prompt(ps,ys='y',cs=1):
    sys.stdout.write(ps)
    ii = raw_input()
    if cs == 0:
        ii = ii.lower()
    if type(ys) == tuple:
        for accept in ys:
            if cs == 0:
                accept = accept.lower()
            if ii == accept:
                return True
    else:
        if ii == ys:
            return True
    return False
fyngyrz
fuente
1
def question(question, answers):
    acceptable = False
    while not acceptable:
        print(question + "specify '%s' or '%s'") % answers
        answer = raw_input()
        if answer.lower() == answers[0].lower() or answers[0].lower():
            print('Answer == %s') % answer
            acceptable = True
    return answer

raining = question("Is it raining today?", ("Y", "N"))

Así es como lo haría.

Salida

Is it raining today? Specify 'Y' or 'N'
> Y
answer = 'Y'
Callam Delaney
fuente
1

Aquí está mi opinión, simplemente quería abortar si el usuario no afirmaba la acción.

import distutils

if unsafe_case:
    print('Proceed with potentially unsafe thing? [y/n]')
    while True:
        try:
            verify = distutils.util.strtobool(raw_input())
            if not verify:
                raise SystemExit  # Abort on user reject
            break
        except ValueError as err:
            print('Please enter \'yes\' or \'no\'')
            # Try again
    print('Continuing ...')
do_unsafe_thing()
ThorSummoner
fuente
0

Un ejemplo de Python 3 limpio:

# inputExample.py

def confirm_input(question, default="no"):
    """Ask a yes/no question and return their answer.

    "question" is a string that is presented to the user.
    "default" is the presumed answer if the user just hits <Enter>.
        It must be "yes", "no", or None (meaning
        an answer is required of the user).

    The "answer" return value is True for "yes" or False for "no".
    """
    valid = {"yes": True, "y": True, "ye": True,
             "no": False, "n": False}
    if default is None:
        prompt = " [y/n] "
    elif default == "yes":
        prompt = " [Y/n] "
    elif default == "no":
        prompt = " [y/N] "
    else:
        raise ValueError("invalid default answer: '{}}'".format(default))

    while True:
        print(question + prompt)
        choice = input().lower()
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            print("Please respond with 'yes' or 'no' "
                             "(or 'y' or 'n').\n")

def main():

    if confirm_input("\nDo you want to continue? "):
        print("You said yes because the function equals true. Continuing.")
    else:
        print("Quitting because the function equals false.")

if __name__ == "__main__":
    main()
Ian Smith
fuente