覆盖 from_yaml 以添加自定义 YAML 标签
Overriding from_yaml to add custom YAML tag
覆盖 from_yaml
是否足以从 class 注册标签,或者是否有必要使用 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
与使用我上面提到的方法注册的任何其他构造函数感到困惑。我想我缺少一些基本的东西,因为他们说:
Subclassing YAMLObject is an easy way to define tags, constructors,
and representers for your classes. You only need to override the
yaml_tag attribute. If you want to define your custom constructor and
representer, redefine the from_yaml and to_yaml method
correspondingly.
确实不需要显式注册:
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()
这是
记录为不安全。如果设置 yaml_loader
class 属性,则可以只使用 safe_load
:
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 完成)
注册是在 yaml.YAMLObject
的 metaclass 的 __init__()
中完成的:
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)
因此,您可能以某种方式干扰了完整 class 定义中的初始化。尝试像我一样从一个最小的实现开始,然后在你的 class 上添加你需要的功能,直到出现问题。
覆盖 from_yaml
是否足以从 class 注册标签,或者是否有必要使用 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
与使用我上面提到的方法注册的任何其他构造函数感到困惑。我想我缺少一些基本的东西,因为他们说:
Subclassing YAMLObject is an easy way to define tags, constructors, and representers for your classes. You only need to override the yaml_tag attribute. If you want to define your custom constructor and representer, redefine the from_yaml and to_yaml method correspondingly.
确实不需要显式注册:
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()
这是
记录为不安全。如果设置 yaml_loader
class 属性,则可以只使用 safe_load
:
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 完成)
注册是在 yaml.YAMLObject
的 metaclass 的 __init__()
中完成的:
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)
因此,您可能以某种方式干扰了完整 class 定义中的初始化。尝试像我一样从一个最小的实现开始,然后在你的 class 上添加你需要的功能,直到出现问题。