重写from_yaml
是否足以从类中注册标记,还是必须使用yaml.add_constructor(Class.yaml_tag, Class.from_yaml)
?如果我不使用te add_constructor
方法,则无法识别我的YAML标签。我所拥有的示例:
import yaml
class Something(yaml.YAMLObject):
yaml_tag = u'!Something'
@classmethod
def from_yaml(cls,loader,node):
# Set attributes to None if not in file
values = loader.construct_mapping(node, deep=True)
attr = ['attr1','attr2']
result = {}
for val in attr:
try:
result[val] = values[val]
except KeyError:
result[val] = None
return cls(**result)
这足以使其正常工作吗?我对使用from_yaml
和使用上述方法注册的其他构造函数感到困惑。我想我缺少一些基本知识,因为他们说:
子类化YAMLObject是定义标签,构造函数, 以及您班级的代表。您只需要覆盖 yaml_tag属性。如果要定义自定义构造函数,则 代表,重新定义from_yaml和to_yaml方法 相应地。
答案 0 :(得分:1)
确实不需要显式注册:
import yaml
class Something(yaml.YAMLObject):
yaml_tag = u'!Something'
def __init__(self, *args, **kw):
print('some_init', args, kw)
@classmethod
def from_yaml(cls,loader,node):
# Set attributes to None if not in file
values = loader.construct_mapping(node, deep=True)
attr = ['attr1','attr2']
result = {}
for val in attr:
try:
result[val] = values[val]
except KeyError:
result[val] = None
return cls(**result)
yaml_str = """\
test: !Something
attr1: 1
attr2: 2
"""
d = yaml.load(yaml_str)
给出:
some_init () {'attr1': 1, 'attr2': 2}
但是根本不需要使用PyYAML的load()
有文件证明是不安全的。如果您设置了safe_load
类属性,则只能使用yaml_loader
:
import yaml
class Something(yaml.YAMLObject):
yaml_tag = u'!Something'
yaml_loader = yaml.SafeLoader
def __init__(self, *args, **kw):
print('some_init', args, kw)
@classmethod
def from_yaml(cls,loader,node):
# Set attributes to None if not in file
values = loader.construct_mapping(node, deep=True)
attr = ['attr1','attr2']
result = {}
for val in attr:
try:
result[val] = values[val]
except KeyError:
result[val] = None
return cls(**result)
yaml_str = """\
test: !Something
attr1: 1
attr2: 2
"""
d = yaml.safe_load(yaml_str)
因为它给出了相同的内容:
some_init () {'attr1': 1, 'attr2': 2}
(使用Python 3.6和Python 2.7完成)
在__init__()
元类的yaml.YAMLObject
中进行注册:
class YAMLObjectMetaclass(type):
"""
The metaclass for YAMLObject.
"""
def __init__(cls, name, bases, kwds):
super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
cls.yaml_dumper.add_representer(cls, cls.to_yaml)
因此,也许您在某种程度上干扰了完整类的定义。像我一样,尝试从一个最小的实现开始,然后在需要的类上添加所需的功能,直到出现问题为止。