Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用默认方法优雅地加载YAML配置_Python_Configuration_Yaml_Pyyaml - Fatal编程技术网

Python 使用默认方法优雅地加载YAML配置

Python 使用默认方法优雅地加载YAML配置,python,configuration,yaml,pyyaml,Python,Configuration,Yaml,Pyyaml,我试图找到一种优雅的方法,将存储在YAML文件中的值加载到我的\uuuu init\uuuu函数中,用于多个类。如果我有一个YAML文件,其中包含以下内容: #YAML an_object: var_a: 1 var_b: 2 import yaml class SomeClass(object): def __init__(self, var_a=10, var_b=20, var_c=30): self.var_a = var_a sel

我试图找到一种优雅的方法,将存储在YAML文件中的值加载到我的
\uuuu init\uuuu
函数中,用于多个类。如果我有一个YAML文件,其中包含以下内容:

#YAML
an_object:
  var_a: 1
  var_b: 2
import yaml 

class SomeClass(object):
    def __init__(self, var_a=10, var_b=20, var_c=30):
        self.var_a = var_a
        self.var_b = var_b
        self.var_c = var_c

        with open('config.yaml','r') as stream:
            cfg = yaml.load(stream)['an_object']

            for key, value in cfg.iteritems():
                if hasattr(self, key):
                    exec("self.{} = {}".format(key, value))
使用以下模块:

class SomeClass(object):
    def __init__(self, var_a=10, var_b=20, var_c=30):
        self.var_a = var_a
        self.var_b = var_b
        self.var_c = var_c
如果存在YAML文件中的值,我希望使用它们,否则如果不存在,则使用
\uuu init\uu
方法默认值。我还希望它可以扩展到许多变量(>10),所以我不想尝试/除了每个参数

我的第一反应是做如下事情:

#YAML
an_object:
  var_a: 1
  var_b: 2
import yaml 

class SomeClass(object):
    def __init__(self, var_a=10, var_b=20, var_c=30):
        self.var_a = var_a
        self.var_b = var_b
        self.var_c = var_c

        with open('config.yaml','r') as stream:
            cfg = yaml.load(stream)['an_object']

            for key, value in cfg.iteritems():
                if hasattr(self, key):
                    exec("self.{} = {}".format(key, value))
但是我不想使用
exec
,也不想分配两次变量(这有点混乱)。有更好的方法吗?它还将覆盖非默认函数值,我也不想这样做。

您应该使用:

请注意,这会将值设置为YAML确定的文件中的值的类型。因此,您必须注意这与您在对象中期望的匹配,或者进行显式转换

还请注意,这是非常低效的,因为对于此类的每个实例,都会打开并读取YAML文件。如果您为不同的类创建了许多对象,那么您应该将所有这些类都作为一个
Loader
类的子类,该类是一个单例类,或者在类变量中从yaml读取值,并在值中读取一次,然后您可以从其中的值(而不是从文件)在每个实例化对象中执行此更新

要防止在YAML中存在默认值时分配默认值,必须首先测试这些值是否存在,如果不存在,则采用默认值:

import ruamel.yaml as yaml

class Loader(object):
    _val = None

    @property
    def yaml_values(self):
        if Loader._val is None:
            with open('config.yaml','r') as stream:
                Loader._val = yaml.load(stream)
        return Loader._val

    def get_val(self, object_id, key, default):
        try:
            return self.yaml_values[object_id][key]
        except KeyError:
            return default


class SomeClass(Loader):
    obj_id = 'an_object'

    def __init__(self, var_a=10, var_b=20, var_c=30):
        for key in ['var_a', 'var_b', 'var_c']:
            setattr(self, key,
                    self.get_val(SomeClass.obj_id, key, locals()[key]))

    def __repr__(self):
        return 'SomeClass(var_a={}, var_b={}, var_c={})'.format(
            self.var_a, self.var_b, self.var_c)


sc = SomeClass()
print sc
将打印:

SomeClass(var_a=1, var_b=2, var_c=30)

我意识到在创建对象时最好使用配置,而不是将YAML放在
\uuuu init\uuuu
中:

import yaml 

class SomeClass(object):
    def __init__(self, var_a=10, var_b=20, var_c=30):
        self.var_a = var_a
        self.var_b = var_b
        self.var_c = var_c

if __name__ == 'main':
    with open('config.yaml','r') as stream:
        cfg = yaml.load(stream)
    sc = SomeClass(**cfg)

这将保留默认值,唯一的主要冲突是分配多个关键字,但这是一个简单的解决方法。

您不需要使用
exec
,可以使用
setattr(self,key,value)