如何使python argparse不带前缀的互斥组参数?


78

Python2.7 argparse仅在互斥组中接受可选参数(前缀):

parser = argparse.ArgumentParser(prog='mydaemon')
action = parser.add_mutually_exclusive_group(required=True)
action.add_argument('--start', action='store_true', help='Starts %(prog)s daemon')
action.add_argument('--stop', action='store_true', help='Stops %(prog)s daemon')
action.add_argument('--restart', action='store_true', help='Restarts %(prog)s daemon')

$ mydaemon -h

usage: mydaemon [-h] (--start | --stop | --restart)

optional arguments:
  -h, --help  show this help message and exit
  --start     Starts mydaemon daemon
  --stop      Stops mydaemon daemon
  --restart   Restarts mydaemon daemon

有没有一种方法可以使argparse参数的行为类似于传统的unix守护程序控件:

(start | stop | restart) and not (--start | --stop | --restart) ?

Answers:


75

对于其中的所有功能和选项,argparse我认为您永远不会获得看起来像您想要的“罐头”用法字符串。

也就是说,自您的原始帖子起,您是否查看过子解析器?

这是一个准系统的实现:

import argparse

parser = argparse.ArgumentParser(prog='mydaemon')
sp = parser.add_subparsers()
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon')
sp_stop = sp.add_parser('stop', help='Stops %(prog)s daemon')
sp_restart = sp.add_parser('restart', help='Restarts %(prog)s daemon')

parser.parse_args()

使用-h选项运行此命令将产生:

usage: mydaemon [-h] {start,stop,restart} ...

positional arguments:
  {start,stop,restart}
    start               Starts mydaemon daemon
    stop                Stops mydaemon daemon
    restart             Restarts mydaemon daemon

这种方法的好处之一是能够set_defaults用于每个子解析器,以将函数直接连接到参数。我还为stop和添加了“优美”选项restart

import argparse

def my_stop(args):
    if args.gracefully:
        print "Let's try to stop..."
    else:
        print 'Stop, now!'

parser = argparse.ArgumentParser(prog='mydaemon')

graceful = argparse.ArgumentParser(add_help=False)
graceful.add_argument('-g', '--gracefully', action='store_true', help='tries to terminate the process gracefully')
sp = parser.add_subparsers()
sp_start = sp.add_parser('start', help='Starts %(prog)s daemon')
sp_stop = sp.add_parser('stop', parents=[graceful],
                    description='Stops the daemon if it is currently running.',
                    help='Stops %(prog)s daemon')
sp_restart = sp.add_parser('restart', parents=[graceful], help='Restarts %(prog)s daemon')

# Hook subparsers up to functions
sp_stop.set_defaults(func=my_stop)

# Uncomment when my_start() and 
# my_restart() are implemented
#
# sp_start.set_defaults(func=my_start)
# sp_restart.set_defaults(func=my_restart)

args = parser.parse_args()
args.func(args)

显示以下内容的“帮助”消息stop

$ python mydaemon.py stop -h
usage: mydaemon stop [-h] [-g]

Stops the daemon if it is currently running.

optional arguments:
  -h, --help        show this help message and exit
  -g, --gracefully  tries to terminate the process gracefully

停止“优雅地”:

$ python mydaemon.py stop -g
Let's try to stop...

但是您没有显示如何确定选择了哪个启动停止或重新启动选项。当我尝试查看参数的repr时,没有显示任何子解析器参数。
罗纳尔多·纳西门托

@RonaldoNascimento我想您的问题在这里得到了解决docs.python.org/3/library/…向下滚动一下,有一个使用以下方法解决此问题的示例set_defaults
OriolAbril 18-4-5

@RonaldoNascimento很晚,但是我想我的编辑回答了您的问题。my_stop()的set_defaults()始终存在,但很容易被忽略(甚至被我忽略)。罗纳尔多的评论使我明白了您的问题。而且我不确定您对repr()所做的操作没有显示您的期望。
扎克·杨

78

来自pymotw

import argparse

parser = argparse.ArgumentParser()

group = parser.add_mutually_exclusive_group()
group.add_argument('-a', action='store_true')
group.add_argument('-b', action='store_true')

print parser.parse_args()

输出:

$ python argparse_mutually_exclusive.py -h  
usage: argparse_mutually_exclusive.py [-h] [-a | -b]

optional arguments:  
  -h, --help  show this help message and exit  
  -a  
  -b  

$ python argparse_mutually_exclusive.py -a  
Namespace(a=True, b=False)

$ python argparse_mutually_exclusive.py -b  
Namespace(a=False, b=True)

$ python argparse_mutually_exclusive.py -a -b  
usage: argparse_mutually_exclusive.py [-h] [-a | -b]  
argparse_mutually_exclusive.py: error: argument -b: not allowed with argument -a

版本2

import argparse

parser = argparse.ArgumentParser()

subparsers = parser.add_subparsers(help='commands')

# A list command
list_parser = subparsers.add_parser('list', help='List contents')
list_parser.add_argument('dirname', action='store', help='Directory to list')

# A create command
create_parser = subparsers.add_parser('create', help='Create a directory')
create_parser.add_argument('dirname', action='store', help='New directory to create')
create_parser.add_argument('--read-only', default=False, action='store_true',
                       help='Set permissions to prevent writing to the directory',
                       )

# A delete command
delete_parser = subparsers.add_parser('delete', help='Remove a directory')
delete_parser.add_argument('dirname', action='store', help='The directory to remove')
delete_parser.add_argument('--recursive', '-r', default=False, action='store_true',
                       help='Remove the contents of the directory, too',
                       )

print parser.parse_args(['list', 'a s d', ])
>>> Namespace(dirname='a s d')
print parser.parse_args(['list', 'a s d', 'create' ])
>>> error: unrecognized arguments: create

39

听起来您需要位置参数而不是互斥选项。您可以使用“选择”来限制可能的可接受选项。

parser = ArgumentParser()
parser.add_argument('action', choices=('start', 'stop', 'restart'))

这将产生一个用法行,如下所示:

usage: foo.py [-h] {start,stop,restart}

是的,我看到了,但是选择限制了使用的准确性。我只是在寻找摆脱前缀的方法。
卡洛·皮雷斯

您是什么意思“限制使用的准确性”?用户可以在不提供其中之一的情况下运行脚本吗?
亚当·瓦格纳

当用户发出“ mydaemon -h”时,帮助(用法)不是很清晰,就像为每个参数使用帮助字符串一样。
卡洛·皮雷斯

1
@AdamWagner如果用户传递多个参数该怎么办?例如foo.py start stop
Santosh Kumar 2013年

@SantoshKumar在您的示例中,“ stop”不是第一个位置参数,因此,如果在我上面的示例中仅定义了一个参数,它将导致错误提示它无法识别“ stop”(在您给出的示例中)。如果您定义了第二个位置参数,则“开始”将是第一个的值,而“停止”将是第二个的值(无论碰巧是什么)。
亚当·瓦格纳

13

基于亚当的答案...如果您想指定默认值,则可以始终执行以下操作,以便他们可以有效地将其留空。

import argparse

ActionHelp = """
    Start = Starts the daemon (default)
    Stop = Stops the daemon
    Restart = Restarts the daemon
    """
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)

parser.add_argument('action', nargs = '?', choices=('start', 'stop', 'restart'),
    default = 'start', help = ActionHelp)

print parser.parse_args(''.split())
print
print parser.parse_args('-h'.split())

它将打印:

Namespace(action='start')

usage: program.py [-h] [{start,stop,restart}]

postional arguments:
    {start,stop,restart}
                      Start = Starts the daemon (default)
                      Stop = Stops the daemon
                      Restart = Restarts the daemon

optional arguments:
    -h, --help        show this help message and exit
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.