YAML解析到对象(PyYAML Python3)

2024-05-19 07:58:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下代码:

class Settings:
    def __init__(self, annual_volatility_target):
        self.annual_volatility_target = annual_volatility_target
        self.daily = annual_volatility_target/np.sqrt(252)

def yaml_load(name):
    with open('yaml/' + str(name) + '.yaml', 'r') as ymlfile:
        return yaml.load(ymlfile)

settings = yaml_load("settings")

使用以下YAML:

^{pr2}$

问题是,当我加载settings时,settings.daily没有设置。settings.annual_volatility_target是,不管我是否在{}中这么说。在

如果我手动实例化一个Settings对象(即不使用PyYAML),它可以正常工作。在

我做错什么了?在


Tags: 代码nameselfyamltargetsettingsinitdef
2条回答

一种可能是为Settings编写一个constructor

import yaml
import numpy as np

class Settings:
    def __init__(self, annual_volatility_target):
        self.annual_volatility_target = annual_volatility_target
        self.daily = annual_volatility_target/np.sqrt(252)

def yaml_load(name):
    with open(str(name) + '.yaml', 'r') as ymlfile:
        return yaml.load(ymlfile)

def settings_constructor(loader, node):
    fields = loader.construct_mapping(node)
    return Settings(fields['annual_volatility_target'])

yaml.add_constructor('!v.Settings', settings_constructor)

settings = yaml_load("settings")

print(settings.annual_volatility_target)
print(settings.daily)

我必须使用修改后的yaml文件(我无法使其与注释!!python/object:v.Settings一起工作):

^{pr2}$

PyYAML中的Python对象是通过两个步骤构建的。首先调用__new__(在Constructor.make_python_instance())然后设置属性(在Constructor.set_python_instance_state())。这两步过程是必需的,因为YAML支持对对象的引用,并且如果该对象(间接地)是自引用的,则无法一次性构造它,因为它所依赖的参数(包括自身)还不可用。在

你可以用两种方法来解决这个问题。您可以为Settings定义__setstate__(),它将用dict调用,并从__init__()调用:

import yaml

yaml_str = """\
!!python/object:try.Settings
annual_volatility_target: 0.25
"""

class Settings:
    def __init__(self, annual_volatility_target):
        self.__setstate__({annual_volatility_target: annual_volatility_target})

    def __setstate__(self, kw):
        self.annual_volatility_target = kw.get('annual_volatility_target')
        self.daily = self.annual_volatility_target/np.sqrt(252)

    def __repr__(self):
        return "Setting({}, {})".format(self.annual_volatility_target, self.daily)

settings = yaml.load(yaml_str)

print(settings)

另一个更通用的(非PyYAML)解决方案是在第一次访问时创建daily值:

^{pr2}$

如果您经常访问daily,那么您应该在第一次计算值时将其缓存到例如self._daily中:

class Settings:
    def __init__(self, annual_volatility_target):
        self.annual_volatility_target = annual_volatility_target
        self._daily = None

    @property:
    def daily(self):
         if self._daily is None:  
             self._daily = annual_volatility_target/np.sqrt(252)
         return self._daily

相关问题 更多 >

    热门问题