[英]'argparse' with optional positional arguments that start with dash
我们正在尝试在所使用的命令行工具上构建包装器脚本。 我们想基于包装脚本中的选项设置一些工具参数。 我们还希望能够将本地参数直接写在命令行中,而直接将其传递给命令行工具。
这是我们想出的:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('positional')
parser.add_argument('-f', '--foo', action='store_true')
parser.add_argument('-b', '--bar', action='store_true')
parser.add_argument('native_arg', nargs='*')
args = parser.parse_args()
print (args)
positional
是强制性的。 基于-f
和-b
选项,我们将在工具调用中添加一些其他选项。 此后留下的所有内容(如果有的话)都应视为本机工具参数,并直接提供给该工具。 用-h
调用我们的脚本会产生以下用法:
usage: test.py [-h] [-f] [-b] positional [native_arg [native_arg ...]]
诀窍在于,这些本机参数本身就是工具的选项,并且包含前划线,例如-native0
和-native1
。 我们已经知道带有双破折号的技巧,可以阻止argparse寻找更多选项。 以下调用:
./test.py pos -- -native0 -native1
产生预期的解析参数:
Namespace(bar=False, foo=False, native_arg=['-native0', '-native1'], positional='pos')
但是,尝试在第一个位置参数之后添加选项不起作用。 更具体地说,以下调用:
./test.py pos --foo -- -native0 -native1
产生以下输出:
usage: [...shortened...]
test.py: error: unrecognized arguments: -- -native0 -native1
将可选参数放在位置上:
./test.py --foo pos -- -native0 -native1
似乎工作,因为打印以下内容:
Namespace(bar=False, foo=True, native_arg=['-native0', '-native1'], positional='pos')
甚至更陌生的是,在所有上述情况下,将nargs
的native_arg
的值nargs
为'+'
有效的(当然,请注意,至少要有一个native_arg
)。
我们在Python代码中做错什么了吗,还是这是argparse错误?
当您将不需要的位置参数与可选参数混合使用时, argparse
确实很argparse
(有关错误报告的详细信息,请参阅https://stackoverflow.com/a/47208725/1399279 )。 我没有提出解决此问题的方法,而是要提出一种替代方法。
您应该检查parse_known_args
方法,该方法是针对您所描述的情况而创建的(即,将选项传递给包装的工具)。
In [1]: import argparse
In [2]: parser = argparse.ArgumentParser()
In [3]: parser.add_argument('positional')
In [4]: parser.add_argument('-f', '--foo', action='store_true')
In [5]: parser.add_argument('-b', '--bar', action='store_true')
In [6]: parser.parse_known_args(['pos', '--foo', '-native0', '-native1'])
Out[6]: (Namespace(bar=False, foo=True, positional='pos'), ['-native0', '-native1'])
不像parse_args
,输出parse_known_args
是两元件的元组。 第一个元素是您希望从parse_args
获得的Namespace
实例,它包含由对add_argument
的调用定义的所有属性。 第二个元素是解析器不知道的所有参数的列表。
我个人更喜欢这种方法,因为用户不需要记住有关如何调用程序的任何技巧,或者哪种选择顺序不会导致错误。
这是一个已知问题( https://bugs.python.org/issue15112,argparse:nargs ='*'位置参数如果前面带有选项和另一个位置,则不接受任何项目 )
解析会交替处理位置和可选内容。 在处理positional时,它将尝试处理输入字符串所需的数量。 但是?
或*
positional对[]
表示满意,这是一个空字符串列表。 另一方面, +
至少需要一个字符串
./test.py pos --foo -- -native0 -native1
解析器将'pos'赋予positional
,将[]
赋予native-arg
。 然后将'--foo'赋予其可选值。 剩下的所有弦都不再需要positionals
,因此会引发错误。
输入字符串的分配是使用形式化的regex
字符串匹配来完成的。 想象一下匹配一个看起来像AA?
的模式AA?
。
为了解决这个问题,解析器必须向前看,并延迟处理native-arg
。 我们建议使用补丁程序,但它们尚未投入生产。
@SethMMorton建议使用parse_known_args
是一个很好的建议。
较早的解析器(例如Optparse)处理所有标记的参数,但返回其余的位置参数作为未区分的列表。 由用户来拆分列表。 argparse
增加了命名和解析positionals
,但是该算法在固定nargs
效果最好,并且在可变nargs
过多的情况下会变得nargs
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.