【问题标题】:Python YAML parameter reference (get value from other parameter)Python YAML 参数参考(从其他参数获取值)
【发布时间】:2015-09-04 06:38:32
【问题描述】:

我正在尝试在我的 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,自动设置参数key为可引用对象就好了……

【问题讨论】:

    标签: python yaml pyyaml


    【解决方案1】:

    嗯,我一直在研究解决方案,因为没有什么是我想要的,而且一切都太复杂了,我想死……

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

    效果很好,这是一个例子

    root_path: /root
    script_path: "%root%/scripts"
    

    使用此方法,script_path 将变为/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 文件。我希望你觉得这很有用,我真的这样做,因为这正是我所需要的。

    我使用了百分比% 令牌,但您可以将其更改为您想要的任何内容并更改方法以使其与正则表达式一起使用(正则表达式使用了一些令牌,这就是我使用% 的原因)

    【讨论】:

      【解决方案2】:

      我会稍微调整一下 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 组合中。 data 与普通 Python dict 一样工作。


      ¹ 这是使用ruamel.yaml 完成的,我是其中的作者。它是 PyYAML 的超集,主要用于为数据往返保留评论和其他信息。

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-07-01
          • 2021-05-21
          • 2012-02-23
          • 1970-01-01
          • 2021-12-21
          • 1970-01-01
          相关资源
          最近更新 更多