Argparse:从文件中获取默认值

6

我有一个Python脚本,需要很多参数。 目前我使用configparser读取的configuration.ini文件,但希望允许用户使用命令行覆盖特定的参数。 如果只有两个参数,我可能会使用以下方法:

if not arg1:
    arg1 = config[section]['arg1']

但是我不想对30个参数都这样做。有没有一种简单的方法可以通过命令行获取可选参数,并默认使用config文件?


你应该看一下collections.ChainMap,甚至有一个非常接近你想要的例子。 - Thierry Lathuille
使用default=argparse.SUPPRESS,https://docs.python.org/3/library/argparse.html#default,当没有提供值时将参数保留在命名空间之外。然后使用`update`将`vars(args)`条目添加到包含`config`值的字典中。 - hpaulj
3个回答

7

尝试使用dict.update()来执行以下操作:

import argparse
import configparser

config = configparser.ConfigParser()
config.read('config.ini')
defaults = config['default']

parser = argparse.ArgumentParser()
parser.add_argument('-a', dest='arg1')
parser.add_argument('-b', dest='arg2')
parser.add_argument('-c', dest='arg3')
args = vars(parser.parse_args())

result = dict(defaults)
result.update({k: v for k, v in args.items() if v is not None})  # Update if v is not None

有了这个ini文件的例子:

[default]
arg1=val1
arg2=val2
arg3=val3

并且

python myargparser.py -a "test"

result将包含以下内容:

{'arg1': 'test', 'arg2': 'val2', 'arg3': 'val3'}

1
使用 default=argparse.SUPPRESS,您就不需要使用 None 过滤器了。 - hpaulj

6
您可以使用 collections 模块中的 ChainMap
根据文档:

ChainMap 可以将多个字典或其他映射组合在一起,创建一个可更新的视图。[...]

查找会依次搜索底层映射,直到找到键为止。[...]

因此,您可以创建:
  • 一个包含配置文件中键值对的 config 字典,
  • 一个包含命令行参数的 cmd_line_args 字典。
然后,创建一个 ChainMap:
from collections import ChainMap
combined = ChainMap(cmd_line_args, config)

当您访问combined['arg1']时,首先会在cmd_line_args字典中查找arg1,如果在那里找不到,将返回config[arg1]。 您可以链接任意数量的字典,这使您可以组合任意级别的默认值。


1
您可以使用 parser.set_defaults() 批量覆盖默认值(以便从配置中填充未输入的参数)。方便地,这允许 argparse 参数默认字段指定一个最后的默认值,以防参数在命令行或配置中未提供。但是,参数仍然需要以某种方式添加到解析器中,以便解析器愿意识别它们。大多数情况下,set_defaults() 很有用,如果您已经设置了一个 argparse 解析器,但是您只想覆盖默认值,使其来自配置(如果它们未在命令行上指定)。
import argparse

config = dict(
    a=11,
    b=13,
    c=19
)
parser = argparse.ArgumentParser()

#  add arguments to parser ...
parser.add_argument('-a', type=int)
parser.add_argument('-b', type=int)
parser.add_argument('-c', type=int)

parser.set_defaults(**config)
args = parser.parse_args()
print(args)

如果您没有计划使用已设置所有可用参数的解析器,那么您可以选择使用配置来设置一个(直接为每个参数给出默认值,因此无需执行额外的set_defaults()步骤:
import argparse

parser = argparse.ArgumentParser()
config = dict(
    a=11,
    b=13,
    c=19
)

for key, value in config.items():
    parser.add_argument(f'-{key}', default=value, type=type(value))

args = parser.parse_args()
print(args)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接