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

How to pass a parameter to a class constructor called by yaml.load_all

我有一个描述我的对象的 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)

在初始化时,主要使用它来加载数据

 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 函数调用的父 class 加载的,我不知道如何给一个参数告诉路径值。

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

  • 您可以创建一个 Load 工厂对象,并在 load_constructor 调用工厂而不是直接 Load 中设置 path on factory。
  • 您可以将 load_constructor 变成 class 的实例,在该实例上设置 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__() 的值(因为 key 当然可以),也需要定义 param,所以我引用了它。

运行 以上(在 Python3 下)会给你:

data file: /my/path/to/csv/file.csv