Python YAML参数引用(从其他参数获取值)

Python YAML参数引用(从其他参数获取值),python,yaml,pyyaml,Python,Yaml,Pyyaml,我试图在Python脚本中使用YAML配置文件,我发现的问题之一是我无法访问其他属性,因此我需要复制大量内容 比如说 root_path: /root script_path: root_path + /scripts 当然,这是不存在的,但是有什么方法可以做到这一点吗?因为有很多内容我无法复制,因为当一个内容改变时,我需要在任何地方都改变它 我还研究了如何创建自己的连接函数 root_path: &ROOT /root script_path: !join [*ROOT, '/scr

我试图在Python脚本中使用YAML配置文件,我发现的问题之一是我无法访问其他属性,因此我需要复制大量内容

比如说

root_path: /root
script_path: root_path + /scripts
当然,这是不存在的,但是有什么方法可以做到这一点吗?因为有很多内容我无法复制,因为当一个内容改变时,我需要在任何地方都改变它

我还研究了如何创建自己的连接函数

root_path: &ROOT /root
script_path: !join [*ROOT, '/scripts']


def join(loader, node):
    seq = loader.construct_sequence(node)
    return ''.join([str(i) for i in seq])

yaml.add_constructor('!join', join)

但是每次我都需要设置一个
&VARNAME
,自动将参数键设置为可引用对象会很好…

你不能用YAML真正做到这一点。对于配置文件,您可以改为使用,它允许您插值,使您的示例如下所示:

root_path: /root
script_path: %(root_path)s/scripts 

我只想稍微调整一下YAML解析器:

import ruamel.yaml as yaml
from ruamel.yaml.comments import CommentedMap

yaml_str = """\
root_path: /root   # use this key for expansion of values
script_path: root_path + /scripts
"""

def set_item(self, key, value):
    split_val = value.split(' + ', 1)
    if len(split_val) > 1:
        alt_key = split_val[0].strip()
        if alt_key in self.keys():
            value = self.get(alt_key) + split_val[1]
    self._org__setitem__(key, value)

CommentedMap._org__setitem__ = CommentedMap.__setitem__
CommentedMap.__setitem__ = set_item

data = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)
print yaml.dump(data, Dumper=yaml.RoundTripDumper)
将为您提供:

root_path: /root   # use this key for expansion of values
script_path: /root/scripts
请注意,RoundTripLoader/Dumper组合保留了注释和键的顺序<代码>数据与普通Python
dict
一样工作



这是我作为作者使用的。这是PyYAML的超集,主要目的是为数据往返保存评论和其他信息。

好吧,我一直在研究解决方案,因为没有什么是我想要的,一切都是如此复杂,我想去死

此解决方案将
%something%
字符串转换为
something
的值

这是一个很好的例子

root_path: /root
script_path: "%root%/scripts"
使用此方法,
script\u路径
将变为
/root/scripts

def replace_values(yaml_file):
    def _get(dict, list):
        return reduce(lambda d, k: d[k], list, dict)

    def _replace(obj):
        for k, v in obj.iteritems():
            if isinstance(v, dict):
                _replace(v)
            if isinstance(v, str):
                match = re.match(r'%(.*)%', v)
                if match:
                    reference = match.group(1).split('.')
                    replace = _get(yaml_file, reference)
                    obj[k] = re.sub(r'%.*%', replace, v)

    _replace(yaml_file)
    return yaml_file
使用很简单,只需以正常方式加载
Yaml
文件,然后调用replace

with open(config_file.get(options.env), 'r') as ymlfile:
    config = yaml.load(ymlfile)

config = replace_values(config)
然后我们新的
config
将存储替换的值,当然它不会覆盖原始的
.yml
文件。我希望你觉得这很有用,我真的很有用,因为这正是我所需要的

我使用了一个百分比
%
标记,但您可以将其更改为您想要的任何值,并更改方法以使其与regex一起工作(regex使用了一些标记,这就是我使用
%
的原因)