正确的方式从ArgumentParser获取允许的参数
问题:从现有的argparse.ArgumentParser
对象中访问可能参数的意图/官方方式是什么?
示例:我们假设以下上下文:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', '-f', type=str)
在这里,我想获得允许参数的以下列表:
['-h', '--foo', '--help', '-f']
我发现了下面的解决方法,它为我做了诀窍
parser._option_string_actions.keys()
但是我不满意它,因为它涉及访问一个未正式记录的_
成员。 这项任务的正确选择是什么?
我不认为有一种“更好”的方式来实现你想要的。
如果你真的不想使用_option_string_actions
属性,你可以处理parser.format_usage()
来检索选项,但是这样做,你只会得到简短的选项名称。
如果你想同时使用短名称和长名称,你可以处理parser.format_help()
。
这个过程可以用一个非常简单的正则表达式完成: -+w+
import re
OPTION_RE = re.compile(r"-+w+")
PARSER_HELP = """usage: test_args_2.py [-h] [--foo FOO] [--bar BAR]
optional arguments:
-h, --help show this help message and exit
--foo FOO, -f FOO a random options
--bar BAR, -b BAR a more random option
"""
options = set(OPTION_RE.findall(PARSER_HELP))
print(options)
# set(['-f', '-b', '--bar', '-h', '--help', '--foo'])
或者,您可以先创建一个包含参数解析器配置的字典,然后从其中构建argmuent解析器。 这样一个词典可以将选项名称作为键,将选项配置作为值。 这样做,您可以通过itertools.chain平铺的词典键访问选项列表:
import argparse
import itertools
parser_config = {
('--foo', '-f'): {"help": "a random options", "type": str},
('--bar', '-b'): {"help": "a more random option", "type": int, "default": 0}
}
parser = argparse.ArgumentParser()
for option, config in parser_config.items():
parser.add_argument(*option, **config)
print(parser.format_help())
# usage: test_args_2.py [-h] [--foo FOO] [--bar BAR]
#
# optional arguments:
# -h, --help show this help message and exit
# --foo FOO, -f FOO a random options
# --bar BAR, -b BAR a more random option
print(list(itertools.chain(*parser_config.keys())))
# ['--foo', '-f', '--bar', '-b']
如果我不愿意使用_option_string_actions
,最后一种方法是我会做的。
这开始是一个笑话的答案,但我学到了一些东西 - 所以我会发布它。
假设,我们知道允许的选项的最大长度。 在这种情况下,这是一个很好的答案:
from itertools import combinations
def parsable(option):
try:
return len(parser.parse_known_args(option.split())[1]) != 2
except:
return False
def test(tester, option):
return any([tester(str(option) + ' ' + str(v)) for v in ['0', '0.0']])
def allowed_options(parser, max_len=3, min_len=1):
acceptable = []
for l in range(min_len, max_len + 1):
for option in combinations([c for c in [chr(i) for i in range(33, 127)] if c != '-'], l):
option = ''.join(option)
acceptable += [p + option for p in ['-', '--'] if test(parsable, p + option)]
return acceptable
当然这很迂腐,因为这个问题不需要任何特定的运行时间。 所以我会在这里忽略它。 我也会无视,上面的版本会产生一团乱七八糟的输出,因为我们可以轻易摆脱它。
但更重要的是,这种方法检测到以下有趣argparse
“功能”:
argparse
也会允许--fo
。 这必须是一个错误。 argparse
还会允许-fo
( -fo
foo
设置为o
而没有空间或任何东西)。 这是记录和意图,但我不知道它。 正因为如此,正确的解决方案有点长,并且看起来像这样(只有parsable
更改,我会省略其他方法):
def parsable(option):
try:
default = vars(parser.parse_known_args(['--' + '0' * 200])[0])
parsed, remaining = parser.parse_known_args(option.split())
if len(remaining) == 2:
return False
parsed = vars(parsed)
for k in parsed.keys():
try:
if k in default and default[k] != parsed[k] and float(parsed[k]) != 0.0:
return False # Filter '-fx' cases where '-f' is the argument and 'x' the value.
except:
return False
return True
except:
return False
总结 :除了所有的限制(运行时和固定的最大选项长度)之外,这是正确地尊重真实parser
行为的唯一答案 - 不管它有可能是错误的。 所以,在这里,绝对无用的完美答案。
我不得不同意Tryph的回答。
不太好,但是你可以从parser.format_help()
检索它们:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo', '-f', type=str)
goal = parser._option_string_actions.keys()
def get_allowed_arguments(parser):
lines = parser.format_help().split('n')
line_index = 0
number_of_lines = len(lines)
found_optional_arguments = False
# skip the first lines until the section 'optional arguments'
while line_index < number_of_lines:
if lines[line_index] == 'optional arguments:':
found_optional_arguments = True
line_index += 1
break
line_index += 1
result_list = []
if found_optional_arguments:
while line_index < number_of_lines:
arg_list = get_arguments_from_line(lines[line_index])
if len(arg_list) == 0:
break
result_list += arg_list
line_index += 1
return result_list
def get_arguments_from_line(line):
if line[:2] != ' ':
return []
arg_list = []
i = 2
N = len(line)
inside_arg = False
arg_start = 2
while i < N:
if line[i] == '-' and not inside_arg:
arg_start = i
inside_arg = True
elif line[i] in [',',' '] and inside_arg:
arg_list.append(line[arg_start:i+1])
inside_arg = False
i += 1
return arg_list
answer = get_allowed_arguments(parser)
有可能是一个正则表达式替代上述混乱...
链接地址: http://www.djcxy.com/p/93731.html上一篇: Correct way to get allowed arguments from ArgumentParser