如何创建一个显示整数旁边的选项的命令行提示,并允许使用整数输入选择一个选项?

时间:2018-03-09 03:55:55

标签: python command-line command-line-interface command-line-arguments python-click

如何使用click编写命令行提示符,如下所示:

choose name:
[1] Karen
[2] Bob
[3] Jo
[4] Steve

并调用以下函数:

def print_function(name):
    if name == 'Karen':
        print('CEO')
    elif name == 'Bob':
        print('CFO')
    elif name == 'Jo':
        print('COO')
    elif name == 'Steve':
        print('CIO')
    else:
        raise ValueError('Wrong name')

总之,如何创建一个显示用户选项的命令提示符,并允许他们输入整数来选择对应的那些选项?

另外,如果在从命令行调用函数时使用--name Bob,如何使命令提示符可选?

5 个答案:

答案 0 :(得分:0)

使用继承自select的自定义类,您可以拦截选项处理并显示所需的菜单,然后验证响应,如:

自定义类

click.Option

使用自定义类:

要使用自定义类,请将import click class EnumMenuPromptFromDict(click.Option): def __init__(self, *args, **kwargs): super(EnumMenuPromptFromDict, self).__init__(*args, **kwargs) if 'prompt' not in kwargs: raise TypeError( "'prompt' keyword required for '{}' option".format( args[0][0])) self.choices_dict = self.prompt self.prompt_menu = '\n'.join('[{}] {}'.format(i + 1, name) for i, name in enumerate(self.prompt)) self.prompt = 'Choose from,\n{}\n{}'.format( self.prompt_menu, self.name) def prompt_for_value(self, ctx): """Get entered value and then validate""" while True: value = super(EnumMenuPromptFromDict, self).prompt_for_value(ctx) try: choice = int(value) if choice > 0: return list(self.choices_dict)[choice - 1] except (ValueError, IndexError): if value in self.choices_dict: return value click.echo('Error: {} is not a valid choice'.format(value)) def full_process_value(self, ctx, value): """Convert the entered value to the value from the choices dict""" value = super(EnumMenuPromptFromDict, self).full_process_value( ctx, value) try: return self.choices_dict[value] except (KeyError, IndexError): raise click.UsageError( "'{}' is not a valid choice".format(value), ctx) 参数传递给cls装饰器,如:

@click.option()

其中@click.option('--name', cls=EnumMenuPromptFromDict, prompt=titles) 是一个选择词:

prompt

这是如何工作的?

这是有效的,因为click是一个设计良好的OO框架。 titles = OrderedDict(( ('Karen', 'CEO'), ('Bob', 'CFO'), ('Jo', 'COO'), ('Steve', 'CIO') )) 装饰器通常实例化@click.option()对象,但允许使用click.Option参数覆盖此行为。因此,在我们自己的班级继承cls并过度使用所需的方法是一件相对容易的事。

在这种情况下,我们越过click.Option来拦截命令处理并允许输入菜单号或值。我们还过度click.Option.prompt_for_value()将名称转换为标题。

测试代码:

click.Option.full_process_value()

答案 1 :(得分:-1)

好吧,我不适合询问争论的事情(sys.argv将是一个好的开始),但我可以帮助你解决第一个问题:

choice = int (input ("[1] Karen \n[2] Bob \n[3] Jo \n[4] Steve\n")) - 1
positions = ["CEO", "CFO", "COO", "CIO"]
print (positions [choice])

这基本上利用了有序列表(并从输入中减去1,因为列表从0开始)

答案 2 :(得分:-1)

您可以使用argparse手动构建它。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--name")
args = parser.parse_args()


def print_function(name):
    if name == 'Karen':
        print('CEO')
    elif name == 'Bob':
        print('CFO')
    elif name == 'Jo':
        print('COO')
    elif name == 'Steve':
        print('CIO')
    else:
        raise ValueError('Wrong name')


if args.name:
    print_function(args.name)
else:
    name = input("""
choose name:
[1] Karen
[2] Bob
[3] Jo
[4] Steve
    """.strip())
    print_function(name)

答案 3 :(得分:-1)

这很容易用字典

names = {
    1: 'Karen',
    2: 'Bob',
    3: 'Jo',
    4: 'Steve'
}

使用string.format()发出提示并迭代字典的项目:

str_items = ['[{}] {}\n'.format(val, name) for val, name in names.items()]
prompt = ''.join(str_items)
val = input('Choose name:\n' + prompt))

然后只需将用户输入转换为int,并在字典中查找值

name = names[int(val)]

print('You chose: ' + name)

然后再为标题

再做一次
titles = {
    'Karen': 'CEO',
    'Bob': 'CFO',
    'Jo': 'COO',
    'Steve': 'CIO'
}

print(titles[name])

答案 4 :(得分:-1)

如果只有一个结构来保存数据(名称和职位)而不是两个,那将会很不错。只是为了在人们更改职称或加入或离开时的可维护性,那么你只需要更新一件事而不是两件事(名单列表+标题列表,或者名称和标题字典)。

一种方法是使用元组列表:

people = [("Karen", "CEO"), ("Bob", "CFO"), ("Jo", "COO"), ("Steve", "CIO")]

然后通过名字获得一个人很简单:

def get_person_by_name(name):
    for person in people:
        if person[0] == name:
            return person

除了--name之外,您没有说明需要接受多少其他命令行参数,但如果只是这一个,那么您可以这样做:

if len(sys.argv) == 3 and sys.argv[1] == "--name":
    person_name = sys.argv[2]
    person = get_person_by_name(person_name)
    if not person:
        print("Person '%s' not found" % person_name)

然后,如果你还没有人(没有给出参数,或者给出了一个未找到的名字),那么你可以使用input

def ask_for_person():
    '''Ask which person the user wants'''
    prompt = "\n".join(["[%d] %s" % (num+1, person[0]) for num, person in enumerate(people)])

    while True:
        try:
            person_num = int(input("choose name:\n" + prompt + "\n? "))
            if person_num >=1 and person_num <= len(people):
                return people[person_num - 1]
        except ValueError:
            pass
        print("try again!")

最后你可以打印你的输出:

if not person:
    person = ask_for_person()
print("'%s' is the '%s'" % person)