Python:使用字符串插值实现动态json

5
我创建了一个函数类,用于提供一些云基础设施。
response = self.ecs_client.register_task_definition(
containerDefinitions=[
                {
                    "name": "redis-283C462837EF23AA",
                    "image": "redis:3.2.7",
                    "cpu": 1,
                    "memory": 512,
                    "essential": True,
                },
...

这是一个很长的json,我只展示了开头。

然后,我重构了代码,使用参数代替了硬编码的哈希、内存和CPU。

response = self.ecs_client.register_task_definition(
containerDefinitions=[
                {
                    "name": f"redis-{git_hash}",
                    "image": "redis:3.2.7",
                    "cpu": {num_cpu},
                    "memory": {memory_size},
                    "essential": True,
                },
...

在编写这段代码之前,我已经从配置文件中读取了git_hashnum_cpumemory_size的值。

现在,我还想从一个文件中读取整个json数据。

问题在于,如果我将{num_cpu}等内容保存在文件中,字符串插值功能将无法工作。

如何从我的逻辑中提取json并仍然使用字符串插值或变量?


为什么不把所有内容(整个JSON)放在一个简单的文件中?为什么需要将一些配置选项分离到不同的配置文件中? - user7970318
@AlexandruStoica 因为JSON是静态的,而一些变量是动态的。 - Alon
1个回答

3
您可以使用string中的Template
{
    "name": "redis-${git_hash}",
    "image": "redis:3.2.7",
    "cpu": ${num_cpu},
    "memory": ${memory_size},
    "essential": true
}

from string import Template
import json

if __name__ == '__main__':
    data = dict(
        num_cpu = 1, 
        memory_size = 1,
        git_hash = 1
    )
    with open('test.json', 'r') as json_file:
        content = ''.join(json_file.readlines())
        template = Template(content)
        configuration = json.loads(template.substitute(data))
        print(configuration)

# {'name': 'redis-1', 'image': 'redis:3.2.7', 'cpu': 1, 'memory': 1, 'essential': True}

观点:我认为整体方法是错误的。这种方法不像其他方法那样受欢迎是有原因的。你可以将配置分成两个文件(1)一份静态选项清单和(2)你紧凑可变的配置,并在你的代码中组合它们。

编辑: 你可以创建一个对象,从一个标准的(静态或可变)JSON文件FileConfig读取配置。然后使用另一个对象ComposedConfig将它们组合起来。

这将允许你扩展行为,并在混合中添加运行时配置。这样你的JSON文件中的配置就不再依赖于运行时参数,你可以将系统中可变的内容与静态内容分开。

PS: get方法只是用来解释组合行为的例子; 你可以使用其他方法/设计。

import json
from abc import ABC, abstractmethod 


class Configuration(ABC):
    
    @abstractmethod
    def get(self, key: str, default: str) -> str:
        pass


class FileConfig(Configuration):

    def __init__(self, file_path):
        self.__content = {}
        with open(file_path, 'r') as json_file:
            self.__content = json.load(json_file)
            
    def get(self, key: str, default: str) -> str:
        return self.__content.get(key, default)


class RunTimeConfig(Configuration):
    def __init__(self, option: str):
        self.__content = {'option': option}
    
    def get(self, key: str, default: str) -> str:
        return self.__content.get(key, default)


class ComposedConfig:

    def __init__(self, first: Configuration, second: Configuration):
        self.__first = first
        self.__second = second

    def get(self, key: str, default: str) -> str:
        return self.__first.get(key, self.__second.get(key, default))


if __name__ == '__main__':
    static = FileConfig("static.json")
    changeable = FileConfig("changeable.json")
    runTime = RunTimeConfig(option="a")
    config = ComposedConfig(static, changeable)
    alternative = ComposedConfig(static, runTime)
    print(config.get("image", "test")) # redis:3.2.7
    print(alternative.get("option", "test")) # a

如果我尝试将该JSON保存到文件中,PyCharm会报错:JSON标准不允许这样的令牌。 - Alon
你能否写一个分离文件的例子,就像你最后建议的那样? - Alon
PyCharm只是检查您的JSON文件结构,因为它格式不正确,所以会发出警告,但您仍然可以毫无问题地运行Python应用程序。您还可以将JSON内容保存为.txt文件以忽略此问题。 - user7970318
1
最终我选择了使用Template类的第一种解决方案。它非常完美。我通过像这样存储{num_cpu}等内容来解决错误: "${num_cpu}"。Mulțumesc! - Alon

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