我自己还没有尝试过,但我认为你应该可以使用
PyYAML优雅地完成这个任务,使用他们所谓的
"representers"和"resolvers"。
编辑
在与发布者进行了广泛的评论交流后,以下是使用PyYAML实现所需行为的方法。
重要说明:如果一个Persistable实例有另一个这样的实例作为属性,或者以某种方式包含在其属性之一中,则包含的Persistable实例将不会保存到另一个单独的文件中,而是将内联保存在与父Persistable实例相同的文件中。据我所知,这种限制也存在于发布者基于pickle的系统中,并且可能适用于他/她的用例。我还没有找到一种优雅的解决方案,不涉及yaml.representer.BaseRepresenter的黑客攻击。
import yaml
from functools import partial
class Persistable(object):
_unique = 0
def __init__(self, *args, **kw):
Persistable._unique += 1
self.persistent_id = ("%s.%d" %
(self.__class__.__name__, Persistable._unique))
def persistable_representer(dumper, data):
id = data.persistent_id
print "Writing to file: %s" % id
outfile = open(id, 'w')
outfile.write(yaml.dump(data))
outfile.close()
return dumper.represent_scalar(u'!xref', u'%s' % id)
class PersistingDumper(yaml.Dumper):
pass
PersistingDumper.add_representer(Persistable, persistable_representer)
my_yaml_dump = partial(yaml.dump, Dumper=PersistingDumper)
def persistable_constructor(loader, node):
xref = loader.construct_scalar(node)
print "Reading from file: %s" % id
infile = open(xref, 'r')
value = yaml.load(infile.read())
infile.close()
return value
yaml.add_constructor(u'!xref', persistable_constructor)
class Foo(Persistable):
def __init__(self):
self.one = 1
Persistable.__init__(self)
class Bar(Persistable):
def __init__(self, foo):
self.foo = foo
Persistable.__init__(self)
foo = Foo()
bar = Bar(foo)
print "=== foo ==="
dumped_foo = my_yaml_dump(foo)
print dumped_foo
print yaml.load(dumped_foo)
print yaml.load(dumped_foo).one
print "=== bar ==="
dumped_bar = my_yaml_dump(bar)
print dumped_bar
print yaml.load(dumped_bar)
print yaml.load(dumped_bar).foo
print yaml.load(dumped_bar).foo.one
baz = Bar(Persistable())
print "=== baz ==="
dumped_baz = my_yaml_dump(baz)
print dumped_baz
print yaml.load(dumped_baz)
从现在开始,当你想要将Persistable类的实例保存到单独的文件中时,请使用
my_yaml_dump
代替
yaml.dump
。但是不要在
persistable_representer
和
persistable_constructor
中使用它!没有特殊的加载函数是必要的,只需使用
yaml.load
。
哎呀,这需要一些工作...我希望这可以帮到你!
persistent_id
机制的功能,但使用可由人编辑的格式?(但你是对的,最后一部分可能会引起一些混淆 - 我会尝试重新措辞) - Riccardo Murri