【问题标题】:python json config variable key replacement in multiple levels of hierarchy多层次层次结构中的python json config变量键替换
【发布时间】:2020-03-19 15:37:46
【问题描述】:

我打算使用 json 作为配置文件,目前我有一个这样的配置

{
  "settings": {
    "general": "root",
    "folder": "folder_test"
  },
  "TEST1": {
    "dataone": "xyz",
    "testing": {
      "a": "$general/$folder/test.png",
      "b": "$general/$folder/test.png"
    },
    "SOMELIST": [
      "$general/$folder/test.png",
      "$general/$folder/test.png"
    ]
  },
  "TEST2": {
    "dataone": "xyz",
    "testing": {
      "a": "$general/$folder/test.png",
      "b": "$general/$folder/test.png"
    },
    "something": {
        "test_data": {
          tester: {
            "abc": "$general/$folder/test.png",
            "zxv": "$general/$folder/test.png"
          }
        }
    }
  }
}

我的目的是让设置部分填充静态路径,例如根目录和文件夹名称等,并让配置的其余部分贯穿整个配置层次结构,以将设置用作变量。这是为了路径和文件夹的目的,如果根或新文件夹更改/添加,我以后维护时不会有任何问题。

我希望配置能够在以后的任何层次结构中使用所有设置变量,即使将来有新添加的级别也是如此。

到目前为止,我只能循环一个级别,但不确定如何访问多个级别。

for k, v in config.items():
    for key in config.keys():
        if key in v:
            config[k] = v.replace("$" + key, config[key])

在 stackoverflow 的另一个主题中找到了这个,但这只是一个级别。我不确定如何在这里构建一个可以包含多个级别的通用级别。

【问题讨论】:

    标签: python json config


    【解决方案1】:

    您是否考虑过在将变量解析为 JSON 之前只替换变量,而不是单独替换每个项目的变量?那是更少的内存/计算成本,而且应该更容易。

    config = ""
    with open("config.json") as f:
        config = f.read().replace("$variable", "stackoverflow")
    
    parsed_config = your_parser(config)
    

    编辑:编写了递归替换函数。我希望你能阅读并从中学习。

    import json
    
    call_counter = 0
    
    def replace_string(value: str, template_vars: {}) -> object:
        """
        Replaces template strings in value, by the values in template_vars. 
        """
        for template, newValue in template_vars.items():
            value = value.replace("${}".format(template), newValue)
    
        return value
    
    
    def replace_recursive(json_obj: object, template_vars: {}) -> {}:
        """
        Recursively unpacks and replaces items in a multi-dimensional dict/list/item json object.
        """
        # For each item at this level 
        for key, value in json_obj.items():
            # If the value is a string, replace it
            if isinstance(value, str):
                json_obj[key] = replace_string(value, template_vars)        
    
            # If the item is a list, we need to do something for each value
            elif isinstance(value, list):
                # Enumate unpacks an index with each value
                for index, item in enumerate(value):
                    # If it's a string, we can replace it 
                    if isinstance(item, str):
                        value[index] = replace_string(item, template_vars)
                    # If it's not, we need to do more work. 
                    else:
                        value[index] = replace_recursive(item, template_vars)
    
            # If it's a dict, use this function again to unpack/replace the values
            else:
                json_obj[key] = replace_recursive(value, template_vars)
    
        return json_obj
    
    if __name__ == "__main__":
    
        template_vars = {}
    
        # Read our file
        with open("example.json") as f:
            json = json.load(f)
    
        # Read our settings
        template_vars = json['settings']
    
        # Drop our settings block (don't if you don't want to)
        json.pop('settings')
    
        json = replace_recursive(json, template_vars)
        print(json)
    

    这使用了相当多的函数调用。这个配置不是问题,但可能是另一个问题。

    【讨论】:

    • 这种方式可能更通用,而不是在添加新设置路径时需要维护?在这种情况下有点像半。
    猜你喜欢
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-23
    • 1970-01-01
    • 2014-03-18
    • 1970-01-01
    相关资源
    最近更新 更多