当对象之一为嵌套类时,PyYaml无法从字符串加载YAML

时间:2019-09-09 12:48:30

标签: python yaml

首先,让我介绍一个可行的简单示例。

import yaml


class Child:
    def __init__(self):
        self.nc1 = 11
        self.nc2 = 22


class WorkingParent:

    def __init__(self):
        self.p1 = 11
        self.p2 = 22
        self.nc = Child()


parent = WorkingParent()
yaml_parent_str = yaml.dump(parent)

print("**** yaml_parent_str ***")
print(yaml_parent_str)

print("**** parent_from_yaml_str ***")
parent_from_yaml_str = yaml.load(yaml_parent_str)
print(parent_from_yaml_str)

此控制台输出如下所示,这是正确的。 YAML能够从str yaml_parent_str

创建对象
**** yaml_parent_str ***
!!python/object:__main__.WorkingParent
nc: !!python/object:__main__.Child {nc1: 11, nc2: 22}
p1: 11
p2: 22

**** parent_from_yaml_str ***
<__main__.WorkingParent object at 0x000001A5BF200470>

现在让我们看看什么不起作用

import yaml


class NotWorkingParent:
    class NestedChild:
        def __init__(self):
            self.nc1 = 11
            self.nc2 = 22

    def __init__(self):
        self.p1 = 11
        self.p2 = 22
        self.nc = NotWorkingParent.NestedChild()


parent = NotWorkingParent()
yaml_parent_str = yaml.dump(parent)

print("**** yaml_parent_str ***")
print(yaml_parent_str)

print("**** parent_from_yaml_str ***")
parent_from_yaml_str = yaml.load(yaml_parent_str)
print(parent_from_yaml_str)

结果如下。您会看到YAML无法通过str yaml_parent_str创建对象。

**** yaml_parent_str ***
!!python/object:__main__.NotWorkingParent
nc: !!python/object:__main__.NestedChild {nc1: 11, nc2: 22}
p1: 11
p2: 22

**** parent_from_yaml_str ***
yaml.constructor.ConstructorError: while constructing a Python object
cannot find 'NestedChild' in the module '__main__'
  in "<unicode string>", line 2, column 5:
    nc: !!python/object:__main__.NestedC ... 
        ^

您可以看到问题出在YAML lib认为NestedClass

nc: !!python/object:__main__.NestedChild {nc1: 11, nc2: 22}

代替

nc: !!python/object:__main__.NotWorkingParent.NestedChild {nc1: 11, nc2: 22}

这怎么解决???

1 个答案:

答案 0 :(得分:0)

告诉PyYAML应该用于类的标记

import yaml

class Parent(yaml.YAMLObject):
    yaml_tag = u'!Parent'
    yaml_loader = yaml.SafeLoader
    class NestedChild(yaml.YAMLObject):
        yaml_tag = u'!Child'
        yaml_loader = yaml.SafeLoader
        def __init__(self):
            self.nc1 = 11
            self.nc2 = 22

    def __init__(self):
        self.p1 = 11
        self.p2 = 22
        self.nc = Parent.NestedChild()

parent = Parent()
yaml_parent_str = yaml.dump(parent)

print("**** yaml_parent_str ***")
print(yaml_parent_str)

print("**** parent_from_yaml_str ***")
parent_from_yaml_str = yaml.safe_load(yaml_parent_str)
print(parent_from_yaml_str)

通过衍生自yaml.YAMLObject,您可以使用yaml_tag指定标签。请注意,我还设置了yaml_loader,以便可以使用yaml.safe_load代替yaml.load,这应该总是这样做,因为yaml.load是一个安全问题,因为用户可能会导致代码实例化任意类。