我正在从yaml文件中读取参数,我想使用一个值来产生另一个值。例如,我需要以下参数a和b,b使用a的值。
A:
a: 10
b: a * 10
B:
......
这是我处理文件的方式:
from ruamel.yaml import safe_load, YAMLError
with open(yaml_file, 'r', encoding="utf-8") as hp:
try:
yaml_hparams = safe_load(hp)
for _, V in yaml_hparams.items():
for k, v in V.items():
hparams[k] = v
except YAMLError:
print(YAMLError)
很显然,这为b的值提供了字符串“ a * 10”。我怎么给b加上* 10,即100?
答案 0 :(得分:1)
不适用于YAML。 YAML是一种用于数据序列化的语言,它不是编程语言。
您有多种选择。一种是使用像Jinja这样的模板语言来预处理YAML并计算值。使用Jinja预处理YAML是在Ansible和SaltStack等工具中完成的,因此这是一种相当普遍的做法。但是,请注意Jinja不了解YAML的结构,因此您需要注意空格。
示例:
{% set val = 10 %}
A:
a: {{ val }}
b: {{ val * 10 }}
很明显,在加载YAML之前,您需要在输入上调用Jinja。
另一种选择是使用YAML标记来告诉您的代码如何对这些值进行后处理,并在其中实现它:
A:
a: &val 10
b: !prod [*val, 10]
代码类似于
from ruamel.yaml import safe_load, SafeLoader, YAMLError
import functools
def prod_constructor(loader, node):
return functools.reduce(lambda x, y: x * y, loader.construct_sequence(node))
SafeLoader.add_constructor(u'!prod', prod_constructor)
with open(yaml_file, 'r', encoding="utf-8") as hp:
try:
yaml_hparams = safe_load(hp)
for _, V in yaml_hparams.items():
for k, v in V.items():
hparams[k] = v
except YAMLError:
print(YAMLError)
答案 1 :(得分:0)
这是一个简单的概念证明,用于说明使用内置eval()
函数执行此操作的可行性,正如我在评论中所建议的那样。因此,它具有一些局限性,例如无法处理“前向引用”,但我认为,如果需要,可以克服许多限制。
import json
from ruamel.yaml import safe_load, YAMLError
yaml_file = 'test_refs.yaml'
hparams = {}
with open(yaml_file, 'r', encoding="utf-8") as hp:
try:
yaml_hparams = safe_load(hp)
for _, V in yaml_hparams.items():
for k, v in V.items():
hparams[k] = v
except YAMLError as exc:
print(exc)
print('Before:')
print(json.dumps(hparams, indent=4)) # Pretty-print result.
# Interpolate values with eval()
hparams['__builtins__'] = None # Prevents access to built-ins.
for key, value in list(hparams.items()):
if isinstance(value, str):
try:
hparams[key] = eval(value, hparams)
except (NameError, TypeError):
pass # Possible forward-reference, ignore.
del hparams['__builtins__'] # No longer needed.
print()
print('After:')
print(json.dumps(hparams, indent=4))