Python:带字符串插值的动态 json
Python: dynamic json with string interpolation
我创建了一个 class 函数来提供一些云基础设施。
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_hash
、num_cpu
和 memory_size
的值。
现在,我还想从文件中读取整个 json。
问题是如果我在文件中保存 {num_cpu}
等,字符串插值将不起作用。
如何从我的逻辑中提取 json 并仍然使用字符串插值或变量?
您可以使用 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
.
这将允许您扩展行为,并在混合中添加,例如,run-time 配置。这样,JSON 文件中的配置不再依赖于 run-time 参数,并且您可以将系统中的可变内容与静态内容分开。
PS:get
方法只是一个解释组合行为的例子;你可以使用其他 methods/designs.
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
我创建了一个 class 函数来提供一些云基础设施。
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_hash
、num_cpu
和 memory_size
的值。
现在,我还想从文件中读取整个 json。
问题是如果我在文件中保存 {num_cpu}
等,字符串插值将不起作用。
如何从我的逻辑中提取 json 并仍然使用字符串插值或变量?
您可以使用 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
.
这将允许您扩展行为,并在混合中添加,例如,run-time 配置。这样,JSON 文件中的配置不再依赖于 run-time 参数,并且您可以将系统中的可变内容与静态内容分开。
PS:get
方法只是一个解释组合行为的例子;你可以使用其他 methods/designs.
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