python-3.x - 使用 yaml 覆盖命名空间

标签 python-3.x yaml parameter-passing

问题陈述

我希望 python 模块中支持的选项可以用 .yaml 文件覆盖,因为在某些情况下需要使用非默认值指定太多选项。

我实现的逻辑如下。

parser = argparse.ArgumentParser()
# some parser.add statements that comes with default values
parser.add_argument("--config_path", default=None, type=str,
                    help="A yaml file for overriding parameters specification in this module.")
args = parser.parse_args()

# Override parameters
if args.config_path is not None:
    with open(args.config_path, "r") as f:
        yml_config = yaml.safe_load(f)
    for k, v in yml_config.items():
        if k in args.__dict__:
            args.__dict__[k] = v
        else:
            sys.stderr.write("Ignored unknown parameter {} in yaml.\n".format(k))

问题是,对于某些选项,我有特定的函数/lambda 表达式来转换输入字符串,例如:

parser.add_argument("--tokens", type=lambda x: x.split(","))

为了在解析 YAML 中的选项规范时应用相应的功能,添加这么多 if 语句似乎不是一个好的解决方案。当 parser 对象中引入新选项时,维护一个会相应更改的字典似乎是多余的。是否有任何解决方案可以获取 parser 对象中每个参数的 type

最佳答案

如果您使用 add_argument 添加到解析器的元素以 -- 开头,那么它们 实际上是可选的,通常称为选项。你可以找到这些走过 parser 实例的 _get_optonal_actions() 方法的结果。

如果config.yaml看起来像:

tokens: a,b,c

,那么你可以这样做:

import sys
import argparse
import ruamel.yaml


sys.argv[1:] = ['--config-path', 'config.yaml']  # simulate commandline

yaml = ruamel.yaml.YAML(typ='safe')

parser = argparse.ArgumentParser()
parser.add_argument("--config-path", default=None, type=str,
                    help="A yaml file for overriding parameters specification in this module.")
parser.add_argument("--tokens", type=lambda x: x.split(","))
args = parser.parse_args()


def find_option_type(key, parser):
    for opt in parser._get_optional_actions():
        if ('--' + key) in opt.option_strings:
           return opt.type
    raise ValueError

if args.config_path is not None:
    with open(args.config_path, "r") as f:
        yml_config = yaml.load(f)
    for k, v in yml_config.items():
        if k in args.__dict__:
            typ = find_option_type(k, parser)
            args.__dict__[k] = typ(v)
        else:
            sys.stderr.write("Ignored unknown parameter {} in yaml.\n".format(k))

print(args)

给出:

Namespace(config_path='config.yaml', tokens=['a', 'b', 'c'])

请注意:

  • 我正在使用 ruamel.yaml 的新 API。这种方式加载实际上更快 比使用 from ruamel import yaml; yaml.safe_load() 虽然你的配置文件 可能还不够大,无法注意到。
  • 我正在使用文件扩展名 .yaml,按照官方 FAQ 中的建议。您也应该这样做,除非您不能(例如,如果您的 文件系统不允许这样做)。
  • 我在选项字符串--config-path中使用破折号而不是下划线,这是 键入起来更自然,并自动转换为下划线以获得有效 标识符名称

您可能需要考虑一种不同的方法,手动解析 sys.argv --config-path,然后设置 YAML 配置文件中所有选项的默认值并 然后调用 .parse_args() 。按照这个顺序做事可以让你覆盖 命令行,配置文件中的值。如果你按照自己的方式做事,你总是 如果配置文件具有除一个之外的所有正确值,则必须对其进行编辑。

关于python-3.x - 使用 yaml 覆盖命名空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52912678/

相关文章:

python - python 模块中未定义名称

python - openCV:尝试理解从相机代码捕获视频

php - 如何将yaml添加到php服务器docker安装

python-3.x - python yaml更新保留顺序和注释

javascript - 将参数传递给 GET-Request

python-3.x - 尽管在同一目录中,但 .env 文件内容在 docker compose 构建期间未被替换

python - 如何使用 application/x-www-form-urlencoded 在 python 中发出原始数据发布请求

python - 使用 python 在给定输入参数的文件中追加一行

flutter - initState() 中的变量未初始化

javascript - 将 javascript 参数从对象构造函数传递到对象的方法?