Python 当一个选项放在其余位置参数之前时,为什么argparse会失败?

Python 当一个选项放在其余位置参数之前时,为什么argparse会失败?,python,argparse,Python,Argparse,考虑使用python 3.7.2在scratch.py中的这个测试argparse示例: import sys import argparse import yaml def get_args(): parser = argparse.ArgumentParser() parser.add_argument('--sound', nargs='?', default=None) parser.add_argument('greeting') parser.ad

考虑使用python 3.7.2在scratch.py中的这个测试argparse示例:

import sys
import argparse
import yaml


def get_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('--sound', nargs='?', default=None)
    parser.add_argument('greeting')
    parser.add_argument('name')
    parser.add_argument('params', nargs='*')
    return vars(parser.parse_args(sys.argv[1:]))


def main():
    print(yaml.dump((get_args())))


if __name__ == "__main__":
    main()
如果我使用它:

(websosadmin) ~/wk/cliosoft/websosadmin/sosadmin_cli $ python scratch.py hello john loud red
greeting: hello
name: john
params:
- loud
- red
sound: null

(websosadmin) ~/wk/cliosoft/websosadmin/sosadmin_cli $ python scratch.py --sound bell hello john loud red
greeting: hello
name: john
params:
- loud
- red
sound: bell

(websosadmin) ~/wk/cliosoft/websosadmin/sosadmin_cli $ python scratch.py hello --sound bell john loud red
greeting: hello
name: john
params:
- loud
- red
sound: bell

(websosadmin) ~/wk/cliosoft/websosadmin/sosadmin_cli $ python scratch.py hello john --sound bell loud red
usage: scratch.py [-h] [--sound [SOUND]] greeting name [params [params ...]]
scratch.py: error: unrecognized arguments: loud red
为什么第四个案例失败了?

hello john --sound bell loud red
解析为:

greeting = 'hello'
name = 'john'
params = []
sound = 'bell'
['loud'、'red']
是剩余的

解析器也可以处理位置和可选属性。它使用正则表达式样式的模式匹配将位置集分配给下一个可选('--sound')。'“问候语”和“姓名”都需要一个字符串。”params'可以接受任何列表('*'),包括空列表。一旦用完了,就没有更多的参数可以使用“loud”和“red”

这是一种狡猾的行为,并不理想。在这个主题上至少有一个bug/问题,但是如果我的记忆是正确的,那就不是一件容易修补的事情

更改为
nargs='+'
应给出正确的解析。

此答案基于的响应

这是argparse中的一个错误,但有一个解决方法:将
parse_args
替换为
parse_mixed_args


这适用于问题中的示例(以及实际应用程序,该应用程序具有许多子命令和不同的标志和位置参数)但是如果使用
argparse.rements
之类的东西,它可能会失败。

更改
nargs='+'
确实正确地解析了第四个示例,但这是一个不正确的规范,因为
python scratch.py hello john--sound bell
现在失败了。params的目的是它可以包含零个或多个参数。您是否有该错误/问题的链接?另一个选项是将其更改为“--parms”;使用标志可以提供更多的控制。或
parse_known_args
收集所有“剩余”字符串。谢谢,parse_mixed_args给出了正确答案。但真正的应用程序使用的是水泥,因此我必须深入研究,看看是否可以在不出现其他问题的情况下更改它。我忘记了
混合
。这将期权和头寸的处理分离开来。它的本意是允许拆分*位置,但作为一个副作用,它会清除此行为。旧的optpass处理可选项,并将其他所有项都放在附加项列表中。