我试图在
Python中使用argparse的fromfile-prefix-chars功能从文件加载我的所有命令行参数,但它一直在抱怨我没有指定一些参数.
代码:
import argparse
def go():
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.add_argument("--option1")
parser.add_argument("--option2", type=int, required=True)
args = parser.parse_args()
if __name__ == "__main__":
go()
参数文件:
--option1 foo
--option2 1234
命令行和输出:
$python testargparse.py @testargs
usage: testargparse.py [-h] [--option1 OPTION1] --option2 OPTION2
testargparse.py: error: argument --option2 is required
你可以看到我在文件中提供了必需的参数,但是argparse没有看到它.
最佳答案 从文档:
Arguments read from a file must by default be one per line … and are treated as if they were in the same place as the original file referencing argument on the command line. So in the example above, the expression [‘-f’, ‘foo’, ‘@args.txt’] is considered equivalent to the expression [‘-f’, ‘foo’, ‘-f’, ‘bar’].
在示例中:
fp.write('-f\nbar')
所以该文件包含:
-f
bar
换句话说,每个文件行对应于命令行中的一个“字”(空白分隔). –option1 = foo是一个单词. –option1 foo被解释为就像在命令行中引用一样,例如. prog.py’ – option1 foo” – option2 1234′
https://docs.python.org/dev/library/argparse.html#argparse.ArgumentParser.convert_arg_line_to_args有一个自定义功能,可以在空格上分割线条.如果你想坚持参数文件,试验一下.
import argparse
with open('args.txt', 'w') as fp:
fp.write('--option1 foo\n--option2 1234') # error
# but works with modifed 'convert...'
#fp.write('--option1=foo\n--option2=1234') # works
#fp.write('--option1\nfoo\n--option2\n1234') # works
def convert_arg_line_to_args(arg_line):
for arg in arg_line.split():
if not arg.strip():
continue
yield arg
"""
default line converter:
def convert_arg_line_to_args(self, arg_line):
return [arg_line]
"""
def go():
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.convert_arg_line_to_args = convert_arg_line_to_args
parser.add_argument("--option1")
parser.add_argument("--option2", type=int, required=True)
args = parser.parse_args(['@args.txt'])
print args
if __name__ == "__main__":
go()
@toes建议使用shlex来解析文件. shlex有一个很好的功能,它会删除不必要的引号.
shlex可用于拆分文件的各行.
def sh_split(arg_line):
for arg in shlex.split(arg_line):
yield arg
parser.convert_arg_line_to_args = sh_split
或者它可以替换整个@file读取方法(_read_args_from_files) – 这应该与@toes应答相同,除了@file字符串可以在命令行中的任何位置(甚至可以重复).
def at_read_fn(arg_strings):
# expand arguments referencing files
new_arg_strings = []
for arg_string in arg_strings:
if not arg_string or not arg_string.startswith('@'):
new_arg_strings.append(arg_string)
else:
with open(arg_string[1:]) as args_file:
arg_strings = shlex.split(args_file.read())
new_arg_strings.extend(arg_strings)
return new_arg_strings
parser._read_args_from_files = at_read_fn
显然,更清洁的生产版本会在ArgumentParser子类中修改这些方法.