如何评估YAML中定义的代数表达式?

时间:2018-07-05 08:23:18

标签: python parsing yaml

我有以下两个单独的YAML文件。

  • val.yaml:在此处定义变量
  • expr.yaml:此处定义表达式

val.yaml

x: 2
y: 3
z: 5

expr.yaml

result: (x + y) * z

parse.py

import yaml

with open('val.yaml', 'r') as stream:
    val = yaml.load(stream)

with open('expr.yaml', 'r') as stream:
    expr = yaml.load(stream)

....

# this should be (2 + 3) * 5 = 25
print expr['result']

如何通过引用expr.yaml中定义的变量来评估val.yaml中定义的表达式?

2 个答案:

答案 0 :(得分:2)

使用sympy最容易做到这一点:

from __future__ import print_function

import ruamel.yaml
from sympy.parsing.sympy_parser import parse_expr

yaml = ruamel.yaml.YAML(typ='safe')
with open('var.yaml') as stream:
    vars = yaml.load(stream)
with open('expr.yaml') as stream:
    expr = yaml.load(stream)

for k in expr:
    l = parse_expr(expr[k], vars)
    print('{}: {}'.format(k, l))

打印(使用Python 2或3):

result: 25
  • 即使您坚持使用Python 2.7,也应该真正开始使用print作为函数,因此应该导入from __future__。计划使用print语句的Python 2.7的使用期限为两年,因此请使用此类前向兼容性导入并习惯于使用它们。
  • 您不应该使用PyYAML的yaml.load(),因为它可能是不安全的,当然,如果其他人正在编辑您的输入文件。使用yaml.safe_load()或使用上面的命令(加载速度也更快)。

答案 1 :(得分:0)

这是一种实现方法,即使我在生产环境中强烈不鼓励使用此方法(应避免使用eval,也应清除输入等)。这个想法是在表达式yaml(在result中遵循相同的命名约定的假设下,执行s替换,迭代yaml中的变量。这里是一个示例:

#!/usr/bin/env python

import yaml

VARS_YAML = """
x: 2
y: 3
z: 5
"""

EXPR_YAML = """
result: (x + y) * z
"""

vars = yaml.load(VARS_YAML)
expr = yaml.load(EXPR_YAML)

for key, value in vars.items(): # for python2: vars.iteritems()
  expr['result'] = expr['result'].replace(key, str(value))

r = eval(expr['result'])
print(r) # for python2: print r
# => 25

此代码适用于python-3(目前我唯一可用的版本),但是将其移至python-2(我认为是您的版本)很简单。如果您希望从文件中加载Yaml:

with open('var.yaml', 'r') as var_file:
  vars = yaml.load(var_file)

绰绰有余。