argparse:如何使互斥参数可选?

22

我想像这样使用我的脚本:

python test.py run
python test.py stop

我的代码看起来是这样的:

parser = argparse.ArgumentParser()
command_group = parser.add_mutually_exclusive_group(required=True)
command_group.add_argument('run', help='run it', action='store_true')
command_group.add_argument('stop', help='stop it', action='store_true')

我执行它时,会出现异常:

ValueError: mutually exclusive arguments must be optional

所以当我添加每个参数时,我尝试添加required=False。然后我会得到另一个异常:

TypeError: 'required' is an invalid argument for positionals

我感到困惑。


为什么要使用互斥组(mutex group)而不是 choices - kennytm
2个回答

24

更好的方法是添加一个位置参数,它可以有两个选项。由于你希望它是可选的,请使用nargs='?',这意味着零次或一次:

一种更好的方法是添加一个单一的位置参数,它可以有两个选项。由于您希望它是可选的,请使用nargs ='?',这意味着零次或一次:

parser = argparse.ArgumentParser()
parser.add_argument('run', help='run or stop', nargs='?', choices=('run', 'stop'))
如果给定了run,则值将为'run'。如果给定了stop,则值将为'stop'。如果两者都没有给定,则值将为None
如果您真的想使用互斥组,我不确定您是否可以按照您想要的方式完全实现它。但是,您可以通过添加连字符使它们成为可选参数:
import argparse

parser = argparse.ArgumentParser()
command_group = parser.add_mutually_exclusive_group()
command_group.add_argument('-run', help='run it', action='store_true')
command_group.add_argument('-stop', help='stop it', action='store_true')
当然,这样做的问题是用户也需要提供连字符,但如果你像那样限制自己,就会遇到这种问题。

当然,这样做的问题是用户也需要提供连字符,但如果你像那样限制自己,就会遇到这种问题。


谢谢,它有效。但是如果我真的想使用互斥组,我应该如何编写代码? - huron
@huron:我不确定你能不能做到。请看我的编辑答案。 - zondo

7
您可以通过使用 nargs='?' 来实现这一点。
parser = argparse.ArgumentParser()
command_group = parser.add_mutually_exclusive_group()
command_group.add_argument('run', help='run it', nargs='?')
command_group.add_argument('stop', help='stop it', nargs='?')

这将允许您使用以下方式调用程序:

python test.py run

或者
python test.py stop

但是不要这样做。
python test.py run stop

2
这个不起作用。在Python 3中,这会导致一个TypeError: __init__() got an unexpected keyword argument 'nargs'错误。 - herrbischoff
@herrbischoff:你是用哪个版本的Python3尝试过这个?即使是最新版本的Python(3.8.3),我也可以让它运行。 - Steen
1
我遇到了与@herrbischoff相同的问题,我的问题是我的语句中有一个action='store_true'。一旦移除了它,它就不再对nargs='?'产生影响了。完整性编辑:在版本3.8.2上。 - L.McCauslin
你不能用 nargs 来实现这个。nargs 定义了在关键字后面有多少个参数会被该关键字消耗。例如,如果你有 --file ,你可以允许用户提供多个文件来进行操作。然后你就可以使用 nargs=+(一个或多个)。但是你在这里使用的 nargs=? 只能消耗一个紧随其后的参数作为你命名的参数。 - erikbstack
1
这个例子不正确。首先,“run”和“stop”只是你的参数的名称,而不是你要输入的实际命令。这些参数是位置性的,这意味着顺序定义了它们的含义。这就是问题所在:解析器应该如何理解你指的是哪个参数?互斥对于可选参数(使用--names)有效,但对于位置参数无效。 - Janos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接