【发布时间】:2018-03-30 03:14:50
【问题描述】:
我正在尝试为某些配置对象制作自定义 YAML 转储程序/加载程序。为简单起见,假设我们要将 Hero 类的对象转储到 hero.yml 文件中。
使用默认 dumper/loader 的示例
class Hero:
yaml_tag = '!Hero'
def __init__(self, name, age):
self.name = name
self.age = age
然后通过ruamel.yaml添加默认的loader/dumper
yaml.register_class(Hero)
然后尝试转储和加载:
h = Hero('Saber', 15)
with open('config.yml', 'w') as fout:
yaml.dump(h, fout)
with open('config.yml') as fin:
yaml.load(fin)
效果很好!
但使用自定义 to_yaml 和 from_yaml 方法失败
但是,当我需要更灵活的行为时,需要自定义 from_yaml 和 to_yaml 方法,就会出现问题。
Hero的实现改为:
class Hero:
yaml_tag = '!Hero'
def __init__(self, name, age):
self.name = name
self.age = age
@classmethod
def to_yaml(cls, representer, data):
return representer.represent_mapping(cls.yaml_tag,
{'name': data.name, 'age': data.age})
@classmethod
def from_yaml(cls, constructor, node):
print(node) # for debug
value = constructor.construct_mapping(node)
return cls(**value)
翻斗机按预期工作。但是加载未能加载 YAML 文件。一个 抛出异常:
243 def check_mapping_key(self, node, key_node, mapping, key, value):
244 # type: (Any, Any, Any, Any, Any) -> None
--> 245 if key in mapping:
246 if not self.allow_duplicate_keys:
247 args = [
TypeError: argument of type 'NoneType' is not iterable
通过print(node)标有for debug的行,加载的节点是:
MappingNode(tag='!Hero', value=[(ScalarNode(tag='tag:yaml.org,2002:str', value='name'), ScalarNode(tag='tag:yaml.org,2002:str', value='Saber')), (ScalarNode(tag='tag:yaml.org,2002:str', value='age'), ScalarNode(tag='tag:yaml.org,2002:int', value='15'))])
不使用默认 dumper/loader 的原因
此示例是显示问题的最小案例,在实际案例中,我试图仅转储对象的一部分,例如
class A:
yaml_tag = '!A'
def __init__(self, name, age):
self.data = {'name': name, 'age': age}
A('Saber', 15) 所需的 YAML 文件是
!A
name: Saber
age: 15
我不知道在这种情况下如何使默认的转储器/加载器工作。
我的错误在哪里导致失败?如何解决这个问题呢?
【问题讨论】:
标签: python yaml ruamel.yaml