繁体   English   中英

'argparse',带有以破折号开头的可选位置参数

[英]'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')

甚至更陌生的是,在所有上述情况下,将nargsnative_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM