在 argparse python3 中查找参数的顺序

Find the order of arguments in argparse python3

我有这个代码

parser = argparse.ArgumentParser()
parser.add_argument('--input')
parser.add_argument('--min')
parser.add_argument('--max')
args = parser.parse_args()

我怎么知道参数的顺序?例如,如果我输入:

python somefile.py --min min --input file.csv

我怎么知道 --min 的位置在 --input 之前,而用户没有输入 --max

我认为从解析器本身获取该信息可能很棘手,但可以从 sys.argv:

轻松获取
def get_arg_index(args: list, name: str):
    return next((i for i, v in enumerate(args) if v.startswith(name)), None)


print(get_arg_index(sys.argv, "--min"))
print(get_arg_index(sys.argv, "--max"))

根据设计 argparse 应该以任何顺序处理 optionals。它们按照它们在命令行中提供的顺序进行解析,但它不保留该顺序的任何记录。没有关键字的 positionals 按照 add_argument 定义的顺序处理。

所有属性都添加到 args 名称空间,并在解析开始时使用它们的默认值。它按 add_argument 顺序执行此操作。在较新的 Python 中,此顺序保留在 args.__dict__ 中(vars(args) 也显示)。

但在print(args)中,属性是按排序顺序显示的。 usage 还保留了 optionals.

的定义顺序

所以对于示例解析器:

In [11]: p.print_usage()                                                        
usage: ipython3 [-h] [--foo FOO] [--test TEST] [--aaa AAA] bar

In [12]: args=p.parse_args(['xxx'])  

In [13]: args                                                                   
Out[13]: Namespace(aaa=None, bar='xxx', foo=None, test=None)  # sorted

In [14]: vars(args)                                                             
Out[14]: {'foo': None, 'bar': 'xxx', 'test': None, 'aaa': None} # definition

In [15]: [a.dest for a in p._actions]                                           
Out[15]: ['help', 'foo', 'bar', 'test', 'aaa']  # definition order

因此,仅使用 argparse 记录命令行中参数出现的顺序很尴尬。从某种意义上说,它违背了 optionals.

的精神

备选方案:

  • 直接使用 sys.argv

  • 自定义actionclass

  • 自定义 Namespace class


想到另一个技巧:

如果defaultargparse.SUPPRESS,默认不加到args。然后我认为 var(args) 顺序将是解析和添加值的顺序。

In [16]: for a in p._actions: a.default=argparse.SUPPRESS  
In [24]: args=p.parse_args(['--test', 'ttt','xxx','--foo=3'])                   
In [25]: args                                                                   
Out[25]: Namespace(bar='xxx', foo='3', test='ttt')
In [26]: vars(args)                                                             
Out[26]: {'test': 'ttt', 'bar': 'xxx', 'foo': '3'}

用户可以重复 optionals,重复覆盖以前的值。