Giao diện dòng lệnh APT giống như có / không có đầu vào?


169

Có cách nào ngắn để đạt được giao diện dòng lệnh APT ( Advanced Gói Tool ) trong Python không?

Ý tôi là, khi người quản lý gói nhắc một câu hỏi có / không theo sau [Yes/no], tập lệnh chấp nhận YES/Y/yes/yhoặc Enter(mặc định Yeslà được gợi ý bằng chữ in hoa).

Điều duy nhất tôi tìm thấy trong các tài liệu chính thức là inputraw_input...

Tôi biết nó không khó để mô phỏng, nhưng thật khó chịu khi viết lại: |


15
Trong Python 3, raw_input()được gọi input().
Tobu

Câu trả lời:


222

Như bạn đã đề cập, cách dễ nhất là sử dụng raw_input()(hoặc đơn giản input()cho Python 3 ). Không có cách tích hợp để làm điều này. Từ công thức 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")

Ví dụ sử dụng:

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

elif choice in valid:Và tôi có thể trả lại một boolean.
Ignacio Vazquez-Abrams

Lựa chọn tốt Ignacio, sửa đổi
đánh dấu

24
Trên thực tế, có một strtobool chức năng trong thư viện standart: docs.python.org/2/distutils/...
Alexander Artemenko

14
Chỉ cần nhớ: raw_input()được gọi input()trong Python3
nachouve

Quả thực siêu hữu ích! Chỉ cần thay thế raw_input()bằng input()Python3.
Muhammad Haseeb

93

Tôi sẽ làm theo cách này:

# 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'")

8
raw_input()được gọi input()trong Python3
gizzmole

49

Có một chức năng strtobooltrong thư viện tiêu chuẩn của Python: http://docs.python.org/2/distutils/apiref.html?highlight=distutils.util#distutils.util.strtobool

Bạn có thể sử dụng nó để kiểm tra đầu vào của người dùng và chuyển đổi nó để Truehoặc Falsegiá trị.


fcó lẽ là viết tắt của Sai, và False == 0, vì vậy tôi có được logic. Tại sao chức năng sẽ trả về một intthay vì một boollà một bí ẩn đối với tôi mặc dù.
François Leblanc

@ FrançoisLeblanc về lý do tại sao nó phổ biến nhất trong Cơ sở dữ liệu. Nếu nó không rõ ràng Falsehoặc 0(Không). Bất cứ điều gì khác, được đánh giá bằng hàm bool đều trở thành đúng và sẽ trả về : 1.
JayRizzo

@JayRizzo Tôi hiểu điều đó và cả hai đều có chức năng tương tự nhau ở hầu hết các khía cạnh. Nhưng nó có nghĩa là bạn không thể sử dụng so sánh singleton, tức là if strtobool(string) is False: do_stuff().
François Leblanc

48

Một cách rất đơn giản (nhưng không phức tạp) để làm điều này cho một lựa chọn duy nhất sẽ là:

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

Bạn cũng có thể viết một hàm đơn giản (cải thiện một chút) xung quanh điều này:

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

Lưu ý: Trên Python 2, sử dụng raw_inputthay vì input.


7
Yêu cách tiếp cận đầu tiên. Ngắn gọn và dễ dàng. Tôi đã sử dụng một cái gì đó nhưresult = raw_input("message").lower() in ('y','yes')
Adrian Shum


24

như được đề cập bởi @Alexander Artemenko, đây là một giải pháp đơn giản sử dụng 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

8
chỉ tò mò ... tại sao sys.stdout.writethay vì print?
Anentropic

2
Lưu ý rằng strtobool()không (từ các thử nghiệm của tôi) yêu cầu a lower(). Điều này không rõ ràng trong tài liệu của nó, tuy nhiên.
Michael - Clay Shirky ở đâu

15

Tôi biết điều này đã được trả lời rất nhiều cách và điều này có thể không trả lời câu hỏi cụ thể của OP (với danh sách các tiêu chí) nhưng đây là những gì tôi đã làm cho trường hợp sử dụng phổ biến nhất và nó đơn giản hơn nhiều so với các câu trả lời khác:

answer = input('Please indicate approval: [y/n]')
if not answer or answer[0].lower() != 'y':
    print('You did not indicate approval')
    exit(1)

điều này không hoạt động với python 2 - raw_inputđã được đổi tên inputtrong python 3 stackoverflow.com/questions/21122540/ Kẻ
Brian Tingle

9

Bạn cũng có thể sử dụng nhắc nhở .

Không biết xấu hổ lấy từ README:

#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

4
Xin lưu ý rằng hành vi của trình nhắc là khá ngược khi bạn đang sử dụng nó với "default = 'no'"; nó sẽ trả về True khi bạn chọn 'không' và Sai khi bạn chọn 'có'.
rem

7

Tôi đã sửa đổi câu trả lời của fmark thành python 2/3 tương thích nhiều pythonic hơn.

Xem mô-đun tiện ích của ipython nếu bạn quan tâm đến vấn đề xử lý lỗi nhiều hơn

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

Tương thích với cả Python 2 và 3, rất dễ đọc. Tôi đã kết thúc bằng cách sử dụng câu trả lời này.
François Leblanc

4

trên 2.7, đây có phải là quá không pythonic?

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

nó nắm bắt bất kỳ biến thể nào của Có ít nhất.


4

Làm tương tự với python 3.x, nơi raw_input()không tồn tại:

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

Không, điều này không hoạt động. Trong nhiều hơn một cách thực sự. Hiện đang cố gắng sửa nó, nhưng tôi nghĩ nó sẽ giống như câu trả lời được chấp nhận sau khi tôi hoàn thành.
Gormador

Tôi đã chỉnh sửa cho bạn anwser @pjm. Vui lòng xem xét việc xem xét nó :-)
Gormador

3

Đối với Python 3, tôi đang sử dụng chức năng này:

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

Hàm strtobool chuyển đổi một chuỗi thành một bool. Nếu chuỗi không thể được phân tích cú pháp, nó sẽ tăng ValueError.

Trong Python 3 raw_input đã được đổi tên thành đầu vào .


2

Bạn có thể thử một cái gì đó giống như mã dưới đây để có thể làm việc với các lựa chọn từ biến 'được chấp nhận' hiển thị ở đây:

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

Đây là mã ..

#!/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

2

Là một người mới lập trình, tôi thấy một loạt các câu trả lời ở trên quá phức tạp, đặc biệt nếu mục tiêu là có một chức năng đơn giản mà bạn có thể chuyển nhiều câu hỏi có / không, buộc người dùng phải chọn có hoặc không. Sau khi quét trang này và một số trang khác, và mượn tất cả các ý tưởng hay khác nhau, tôi đã kết thúc với những điều sau đây:

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

1
Không nên tranh luận được gọi là "câu hỏi" thay vì "câu trả lời"?
AFP_555

1

Còn cái này thì sao:

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

1

Đây là những gì tôi sử dụng:

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

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

Đây là cách tôi làm.

Đầu ra

Is it raining today? Specify 'Y' or 'N'
> Y
answer = 'Y'

1

Đây là trách nhiệm của tôi, tôi chỉ muốn hủy bỏ nếu người dùng không xác nhận hành động.

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

0

Một ví dụ về Python 3 đã được dọn sạch:

# 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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.