如何将参数传递给yaml.load_all调用的类构造函数

时间:2016-05-20 08:50:27

标签: python parsing yaml pyyaml

我有一个YAML文件描述我的对象和

--- !MyData
name: theName
param: parameter
data_file: \\path\to\my\file.csv

我的代码如下

class Load(Parent):
    def __init__(self, name="",
             param = param,
             useDataFile=False,
             data_file = "none",
             **kwargs):

        super().__init__(name=name,
                     data_file = data_file)

def load_constructor(loader, node):
    values = loader.construct_mapping(node, deep=True)  
    return Load(**values)

yaml.add_constructor(u'!Load', load_constructor)

在初始时,main使用它来加载数据

 with open(self.initFile, 'r', newline='') as ymlfile:
     for item in yaml.load_all(ymlfile):
         if type(item) is Load:
              ---- some post init code

一切正常但是因为我的主代码已经知道 data_file 的完整路径,因为它与yaml位于同一目录中, 有没有办法只给出 data_file 的名称而没有完整路径,以便我可以在不编辑yaml配置文件的情况下更改位置?由于 data_file 由通过 yaml.load_all 函数调用的Parent类加载,我不知道如何给出一个告诉路径值的参数。

1 个答案:

答案 0 :(得分:0)

有许多不同的解决方案可以在Load实例中动态获取变量path,包括:

  • 您可以创建加载工厂对象,并在path工厂设置load_constructor直接调用工厂而不是Load
  • 您可以将load_constructor转换为类的实例,在该实例上设置path并使其__call__方法执行构造

后者可以用:

import ruamel.yaml as yaml

yaml_str = """\
--- !MyData
name: theName
param: parameter
data_file: file.csv
"""

class Parent:
    def __init__(self, name, data_file, path=None):
        self._name = name
        self._data_file = (path + data_file) if path is not None else data_file

class Load(Parent):
    def __init__(self, name="",
             param = "param",
             useDataFile=False,
             data_file = "none",
             path=None,
             **kwargs):

        super().__init__(name=name,
                         data_file = data_file, path=path)

class LoadConstructor:
    def __init__(self, path=None):
        self._path = None

    def set_path(self, path):
        self._path = path

    def __call__(self, loader, node):
        values = loader.construct_mapping(node, deep=True)
        values['path'] = self._path
        return Load(**values)

load_constructor = LoadConstructor()
yaml.add_constructor(u'!MyData', load_constructor)

# using the above:
# set the default path
load_constructor.set_path('/my/path/to/csv/')
# parse YAML documents
for item in yaml.load_all(yaml_str):
    if type(item) is Load:
        print('data file:', item._data_file)

请注意,我必须更改构造函数的第一个参数,否则无法构造类型为MyData的YAML对象。如果您将param用作Load.__init__()的值(因为关键当然没问题),也需要定义data file: /my/path/to/csv/file.csv ,所以我引用了它。

运行上面的内容(在Python3下)将为您提供:

config.xml