如何使用 argparse 将输入文件中的值附加到命令行选项?
How can I append the values from an input file to the command line options using argparse?
假设我有一个包含以下内容的 yaml 输入文件 (input.txt):
names: [Bob, Jill]
ages: [22, 31]
county: somewhere
我的解析代码:
import yaml
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--name', default=[], dest='names', action='append')
parser.add_argument('--age', default=[], dest='ages', action='append')
parser.add_argument('--county', dest='county')
parser.add_argument(
'--config-file',
dest='config_file',
type=argparse.FileType(mode='r'))
args = parser.parse_args()
print args
我的问题是:我看到很多网站展示了如何像上面那样为配置文件添加参数。我如何 'parse' 该配置文件并将其中的值添加(附加)到命令行上传递的任何值?
如果我的程序叫做so.py,并且是这样调用的:
so.py --config-file=input.txt --name 'Ralph' --age 40
我想得到
名字 = ['Bob', 'Jill', 'Ralph']
年龄 = [22、31、40]
县 = 'somewhere'
在我的参数中。这可能吗?
有一个参数允许从文件输入,'fromfile-prefix-chars'
https://docs.python.org/3/library/argparse.html#fromfile-prefix-chars
在默认形式下,每行需要一个命令行字符串。但是文档还展示了如何修改它以从每一行中获取多个字符串。您可以采用该想法并将其扩展以处理 Yaml 语法。
但是有些库可以读取配置文件和 yaml 文件。因此,您可以使用 --config-file
参数通过该库读取文件,然后将其结果与 argparse
结果合并。通过将(yaml 和 argparse)都转换为字典并使用 .update
方法,合并可能是最简单的。
Ipython
使用它的配置文件(默认的和用户指定的)来填充它的 argparse
解析器参数。因此,用户配置文件可以覆盖默认值,命令行可以覆盖两者。执行此操作的代码不适合胆小的人,但对于大型项目可能值得研究。
如何进行合并的详细信息取决于 'yaml' 生成的对象。 argparse
args
是类型 argparse.Namespace
的简单对象。有关详细信息,请参阅文档。通常人们只是 args
中的 'read' 个值,但添加或修改值同样容易。如果您愿意,vars(args)
可以将其变成字典。
使用 yaml.load
(并稍微简化 argparse):
import yaml
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--names', action='append')
parser.add_argument('--ages', action='append')
parser.add_argument('--county', dest='county')
parser.add_argument('--config-file') # automatic - to _ conversion
sample = "--config-file=stack28220581.yaml --name Ralph --age 40".split()
args = parser.parse_args(sample)
# add test that len(args.names)==len(args.ages) ??
with open(args.config_file) as f:
ydict = yaml.load(f)
# {'county': 'somewhere', 'names': ['Bob', 'Jill'], 'ages': [22, 31]}
# add list attributes from args to the corresponding ydict values
for k,v in ydict.items():
av = getattr(args,k,None)
if av and isinstance(v, list):
v.extend(av)
print(ydict)
# {'names': ['Bob', 'Jill', 'Ralph'], 'ages': [22, 31, '40'], 'county': 'somewhere'}
使用prefix_chars
的例子:
def foo(astr):
# custom convert_arg_line_to_args method
# convert 'names: [v1,v2]' into ['--names', v1, '--names', v2, ...]
alist = []
if ':' not in astr:
return astr
field,value = astr.split(':')
value = value.strip()
field = '--'+field
if value.startswith('['):
values = value[1:-1].split(',')
for v in values:
alist.extend([field,v.strip()])
else:
alist.extend([field, value])
return alist
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.convert_arg_line_to_args = foo # could also do this with subclass
parser.add_argument('--names', action='append')
parser.add_argument('--ages', action='append')
parser.add_argument('--county', dest='county')
sample = "@stack28220581.yaml --name Ralph --age 40".split()
args = parser.parse_args(sample)
print(args)
# Namespace(ages=['22', '31', '40'], county='somewhere', names=['Bob', 'Jill', 'Ralph'])
假设我有一个包含以下内容的 yaml 输入文件 (input.txt):
names: [Bob, Jill]
ages: [22, 31]
county: somewhere
我的解析代码:
import yaml
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--name', default=[], dest='names', action='append')
parser.add_argument('--age', default=[], dest='ages', action='append')
parser.add_argument('--county', dest='county')
parser.add_argument(
'--config-file',
dest='config_file',
type=argparse.FileType(mode='r'))
args = parser.parse_args()
print args
我的问题是:我看到很多网站展示了如何像上面那样为配置文件添加参数。我如何 'parse' 该配置文件并将其中的值添加(附加)到命令行上传递的任何值?
如果我的程序叫做so.py,并且是这样调用的:
so.py --config-file=input.txt --name 'Ralph' --age 40
我想得到 名字 = ['Bob', 'Jill', 'Ralph'] 年龄 = [22、31、40] 县 = 'somewhere' 在我的参数中。这可能吗?
有一个参数允许从文件输入,'fromfile-prefix-chars'
https://docs.python.org/3/library/argparse.html#fromfile-prefix-chars
在默认形式下,每行需要一个命令行字符串。但是文档还展示了如何修改它以从每一行中获取多个字符串。您可以采用该想法并将其扩展以处理 Yaml 语法。
但是有些库可以读取配置文件和 yaml 文件。因此,您可以使用 --config-file
参数通过该库读取文件,然后将其结果与 argparse
结果合并。通过将(yaml 和 argparse)都转换为字典并使用 .update
方法,合并可能是最简单的。
Ipython
使用它的配置文件(默认的和用户指定的)来填充它的 argparse
解析器参数。因此,用户配置文件可以覆盖默认值,命令行可以覆盖两者。执行此操作的代码不适合胆小的人,但对于大型项目可能值得研究。
如何进行合并的详细信息取决于 'yaml' 生成的对象。 argparse
args
是类型 argparse.Namespace
的简单对象。有关详细信息,请参阅文档。通常人们只是 args
中的 'read' 个值,但添加或修改值同样容易。如果您愿意,vars(args)
可以将其变成字典。
使用 yaml.load
(并稍微简化 argparse):
import yaml
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--names', action='append')
parser.add_argument('--ages', action='append')
parser.add_argument('--county', dest='county')
parser.add_argument('--config-file') # automatic - to _ conversion
sample = "--config-file=stack28220581.yaml --name Ralph --age 40".split()
args = parser.parse_args(sample)
# add test that len(args.names)==len(args.ages) ??
with open(args.config_file) as f:
ydict = yaml.load(f)
# {'county': 'somewhere', 'names': ['Bob', 'Jill'], 'ages': [22, 31]}
# add list attributes from args to the corresponding ydict values
for k,v in ydict.items():
av = getattr(args,k,None)
if av and isinstance(v, list):
v.extend(av)
print(ydict)
# {'names': ['Bob', 'Jill', 'Ralph'], 'ages': [22, 31, '40'], 'county': 'somewhere'}
使用prefix_chars
的例子:
def foo(astr):
# custom convert_arg_line_to_args method
# convert 'names: [v1,v2]' into ['--names', v1, '--names', v2, ...]
alist = []
if ':' not in astr:
return astr
field,value = astr.split(':')
value = value.strip()
field = '--'+field
if value.startswith('['):
values = value[1:-1].split(',')
for v in values:
alist.extend([field,v.strip()])
else:
alist.extend([field, value])
return alist
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.convert_arg_line_to_args = foo # could also do this with subclass
parser.add_argument('--names', action='append')
parser.add_argument('--ages', action='append')
parser.add_argument('--county', dest='county')
sample = "@stack28220581.yaml --name Ralph --age 40".split()
args = parser.parse_args(sample)
print(args)
# Namespace(ages=['22', '31', '40'], county='somewhere', names=['Bob', 'Jill', 'Ralph'])