问题 Python argparse:命令行参数,可以是命名的也可以是位置的


我正在尝试制作一个使用该程序的Python程序 argparse 用于解析命令行选项的模块。

我想创建一个可以命名或位置的可选参数。例如,我想要 myScript --username=batman 做同样的事情 myScript batman。我也想要 myScript 没有用户名才有效。这可能吗?如果是这样,怎么办呢?

我尝试了类似下面的代码的各种事情,没有任何成功。

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-u", "--user-name", default="admin")
group.add_argument("user-name", default="admin")
args = parser.parse_args()

编辑: 上面的代码引发了一个例外 ValueError: mutually exclusive arguments must be optional

我在OS X 10.8.4上使用Python 2.7.2。

编辑:我试过Gabriel Jacobsohn的建议,但我无法在所有情况下都能正常工作。

我试过这个:

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-u", "--user-name", default="admin", nargs="?")
group.add_argument("user_name", default="admin", nargs="?")
args = parser.parse_args()
print(args)

并运行 myScript batman 会打印 Namespace(user_name='batman')但是 myScript -u batman 和 myScript --user-name=batman 会打印 Namespace(user_name='admin')

我试过更改名称 user-name 至 user_name 在1日 add_argument 线,这有时导致两者 batman 和 admin 在命名空间或错误中,取决于我如何运行程序。

我试过更改名称 user_name 至 user-name 在第二个 add_argument 但也可以打印出来 Namespace(user-name='batman', user_name='admin') 要么 Namespace(user-name='admin', user_name='batman'),取决于我如何运行该程序。


3806
2017-07-11 15:58


起源

我想提一下,我想做的事情基本上是一样的 确认 做它的 --match 参数。 - Elias Zamaria
请看这个 题 - twil
不知怎的,我没有注意到这个问题。请将此问题标记为该问题的副本。 - Elias Zamaria


答案:


的方式 ArgumentParser 工作,它总是在解析可选参数后检查任何尾随位置参数。因此,如果您的位置参数与可选参数具有相同的名称,并且它不会出现在命令行的任何位置,则可以保证覆盖可选参数(使用其默认值或 没有)。

坦率地说,这对我来说似乎是一个错误,至少在互斥组中使用时,因为如果您明确指定了参数,那将是一个错误。

也就是说,我建议的解决方案是给位置参数赋一个不同的名称。

parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('-u','--username')
group.add_argument('static_username',nargs='?',default='admin')

然后在解析时,使用可选项 用户名 如果存在,否则回落到位置 static_username

results = parser.parse_args()
username = results.username or results.static_username

我意识到这不是一个特别简洁的解决方案,但我认为没有任何答案。


7
2017-07-23 12:30





这是一个我认为可以做你想要的一切的解决方案:

import argparse
if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("-u", "--user-name", default="admin")
    # Gather all extra args into a list named "args.extra"
    parser.add_argument("extra", nargs='*')
    args = parser.parse_args()
    # Set args.user_name to first extra arg if it is not given and len(args.extra) > 0
    if args.user_name == parser.get_default("user_name") and args.extra:
        args.user_name = args.extra.pop(0)
    print args

如果你跑 myScript -u batman 要么 myScript --user-name=batmanargs.user_name 被设定为'蝙蝠侠'。如果你这样做 myScript batmanargs.user_name 又被设定为'蝙蝠侠'。最后,如果你这样做 myScriptargs.user_name 设置为“admin”。

此外,作为额外的奖励,您现在拥有传递给存储在其中的脚本的所有额外参数 args.extra。希望这可以帮助。


4
2017-07-23 02:37



我会改变 args.username = args.extra[0] 至 args.username=args.extra.pop(0),这样它就不会出现在两个地方。 - Perkins
@Perkins:嗯......我喜欢那个。它使脚本更清晰。让我来做 - iCodez
我喜欢你的回答。我做了一个小改动,以避免在两个地方使用默认用户名。 - Elias Zamaria
我决定将赏金奖给@James Holderness。我喜欢你的想法,但James的解决方案向用户表明,对程序的调用不允许同时具有命名用户名和位置用户名。 - Elias Zamaria


尝试使用add_argument方法的“nargs”参数。 这样它对我有用。 现在您可以添加两次用户名, 所以如果你愿意,你必须检查它并引发错误。

import argparse
if __name__ == '__main__':
   parser = argparse.ArgumentParser()
   parser.add_argument("-u", "--user-name", default="admin")
   parser.add_argument("user_name", default="admin", nargs="?")
   args = parser.parse_args()
   print(args)

0
2017-07-11 16:09



我在你的答案中尝试了代码。我跑的时候工作得很好 myScript batman 但随着 myScript -u batman 要么 myScript --user-name=batman,它忽略了我的参数并设置了 user_name 价值 admin。 - Elias Zamaria