我的脚本采用-d,--delimiter作为参数:
parser.add_argument('-d', '--delimiter')
Run Code Online (Sandbox Code Playgroud)
但是当我将它--作为分隔符传递时,它是空的
script.py --delimiter='--'
Run Code Online (Sandbox Code Playgroud)
我知道--参数/参数解析很特殊,但我在表单中使用它--option='--'并引用它。
为什么它不起作用?我正在使用Python 3.7.3
这是测试代码:
#!/bin/python3
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--delimiter')
parser.add_argument('pattern')
args = parser.parse_args()
print(args.delimiter)
Run Code Online (Sandbox Code Playgroud)
当我运行它时,script --delimiter=-- AAA它打印为空args.delimiter。
use*_*ica 19
这看起来像一个错误。你应该报告一下。
中的代码argparse.py是 的开始_get_values,它是用于解析值的主要辅助函数之一:
if action.nargs not in [PARSER, REMAINDER]:
try:
arg_strings.remove('--')
except ValueError:
pass
Run Code Online (Sandbox Code Playgroud)
该代码接收--参数作为列表的单个元素['--']。'--'它尝试从列表中删除,因为当用作--选项结束标记时,该'--'字符串将最终出现在arg_strings其中一个_get_values调用中。然而,当'--'实际参数值是什么时候,代码仍然会删除它,所以arg_strings最终会成为一个空列表而不是单元素列表。
然后,代码通过 else-if 链来处理不同类型的参数(此处省略分支主体以节省空间):
# optional argument produces a default when not present
if not arg_strings and action.nargs == OPTIONAL:
...
# when nargs='*' on a positional, if there were no command-line
# args, use the default if it is anything other than None
elif (not arg_strings and action.nargs == ZERO_OR_MORE and
not action.option_strings):
...
# single argument or optional argument produces a single value
elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
...
# REMAINDER arguments convert all values, checking none
elif action.nargs == REMAINDER:
...
# PARSER arguments convert all values, but check only the first
elif action.nargs == PARSER:
...
# SUPPRESS argument does not put anything in the namespace
elif action.nargs == SUPPRESS:
...
# all other types of nargs produce a list
else:
...
Run Code Online (Sandbox Code Playgroud)
这段代码应该经过第三个分支,
# single argument or optional argument produces a single value
elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
Run Code Online (Sandbox Code Playgroud)
但因为 中缺少参数arg_strings,len(arg_strings)所以为 0。它反而达到了最终的情况,该情况应该处理完全不同类型的参数。该分支最终返回一个空列表,而不是'--'应该返回的字符串,这就是为什么args.delimiter最终是一个空列表而不是'--'字符串。
这个错误也体现在位置参数上。例如,
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('a')
parser.add_argument('b')
args = parser.parse_args(["--", "--", "--"])
print(args)
Run Code Online (Sandbox Code Playgroud)
印刷
Namespace(a='--', b=[])
Run Code Online (Sandbox Code Playgroud)
因为当_get_values处理b参数时,它接收['--']asarg_strings并删除'--'. 在处理a参数时,它接收['--', '--'],表示一个选项结束标记和一个实际--参数值,并且它成功删除了选项结束标记,但在处理 时b,它删除了实际参数值。
已建议修补程序,但尚未应用。Argparse 错误地将“--”处理为选项的参数
In [1]: import argparse
In [2]: p = argparse.ArgumentParser()
In [3]: a = p.add_argument('--foo')
In [4]: p.parse_args(['--foo=123'])
Out[4]: Namespace(foo='123')
Run Code Online (Sandbox Code Playgroud)
意想不到的情况:
In [5]: p.parse_args(['--foo=--'])
Out[5]: Namespace(foo=[])
Run Code Online (Sandbox Code Playgroud)
完全引用通过 - 但我不会讨论如何通过 shell 调用实现这一点:
In [6]: p.parse_args(['--foo="--"'])
Out[6]: Namespace(foo='"--"')
Run Code Online (Sandbox Code Playgroud)
'--' 作为单独的字符串:
In [7]: p.parse_args(['--foo','--'])
usage: ipython3 [-h] [--foo FOO]
ipython3: error: argument --foo: expected one argument
...
Run Code Online (Sandbox Code Playgroud)
双引号的另一个例子:
In [8]: p.parse_args(['--foo','"--"'])
Out[8]: Namespace(foo='"--"')
Run Code Online (Sandbox Code Playgroud)
在 中_parse_known_args,输入被扫描并分类为“O”或“A”。'--' 被处理为
# all args after -- are non-options
if arg_string == '--':
arg_string_pattern_parts.append('-')
for arg_string in arg_strings_iter:
arg_string_pattern_parts.append('A')
Run Code Online (Sandbox Code Playgroud)
我认为“--”之后被删除了,但我还没有找到这部分代码。我也没有发现 '--foo=...' 版本是否被处理。
我隐约记得在处理多次出现的“--”时存在一些错误/问题。迁移到 github 后,我不再argparse像以前那样关注开发情况了。
get_values以。。开始:
def _get_values(self, action, arg_strings):
# for everything but PARSER, REMAINDER args, strip out first '--'
if action.nargs not in [PARSER, REMAINDER]:
try:
arg_strings.remove('--')
except ValueError:
pass
Run Code Online (Sandbox Code Playgroud)
为什么会导致空列表需要更多的思考和测试。
'=' 在 中处理_parse_optional,在第一次扫描期间使用:
# if the option string before the "=" is present, return the action
if '=' in arg_string:
option_string, explicit_arg = arg_string.split('=', 1)
if option_string in self._option_string_actions:
action = self._option_string_actions[option_string]
return action, option_string, explicit_arg
Run Code Online (Sandbox Code Playgroud)
argparse:允许使用 -- 打破 nargs 并进入子解析器