Python 泡菜的替代品';s'persistent_id`?
我一直在使用Python的 用于实现基于精简文件的持久性层的模块。这个 持久层(大型库的一部分)严重依赖pickle的特性 将指定类的对象保存为单独的文件 这种方法的唯一问题是pickle文件不是人 可编辑,我更希望将对象保存为 可通过文本编辑器(如YAML或JSON)进行人类可读和编辑 你知道有哪个库使用人工编辑格式和 提供类似于pickle的Python 泡菜的替代品';s'persistent_id`?,python,json,persistence,yaml,pickle,Python,Json,Persistence,Yaml,Pickle,我一直在使用Python的 用于实现基于精简文件的持久性层的模块。这个 持久层(大型库的一部分)严重依赖pickle的特性 将指定类的对象保存为单独的文件 这种方法的唯一问题是pickle文件不是人 可编辑,我更希望将对象保存为 可通过文本编辑器(如YAML或JSON)进行人类可读和编辑 你知道有哪个库使用人工编辑格式和 提供类似于pickle的持久化\u id?或者, 您是否有在YAML-or基础上实施它们的建议 基于JSON的序列化库,无需重写 泡菜?我自己还没有试过,但我认为你应该能够优雅
持久化\u id
?或者,
您是否有在YAML-or基础上实施它们的建议
基于JSON的序列化库,无需重写
泡菜?我自己还没有试过,但我认为你应该能够优雅地使用他们所说的东西 编辑 在与海报进行了广泛的评论交流之后,下面是一个使用PyYAML实现所需行为的方法 重要提示:如果一个
Persistable
实例有另一个这样的实例作为属性,或者以某种方式包含在它的一个属性中,那么包含的Persistable
实例将不会保存到另一个单独的文件中,相反,它将以内联方式保存在与父持久化
实例相同的文件中。据我所知,OP基于pickle的系统中也存在这一限制,对于他/她的用例来说可能是可以接受的。我还没有找到一个优雅的解决方案,它不涉及黑客yaml.representer.BaseRepresenter
import yaml
from functools import partial
class Persistable(object):
# simulate a unique id
_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)
# example use, also serves as a test
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)
从现在起,如果要将持久化
类的实例保存到单独的文件中,请使用my_yaml\u dump
而不是yaml.dump
。但是不要在persistable\u representer
和persistable\u构造函数中使用它!无需特殊加载功能,只需使用yaml.load
唷,这花了不少功夫。。。我希望这有帮助 如果没有对持久性系统的目的或要求的任何描述,就很难对如何实现持久性系统提出建议。@taleinat这个问题的范围比实现持久性系统的范围要窄:是否有任何库提供类似于pickle的persistent\u id
机制的功能,但使用的是人类可编辑的格式?(但你是对的,最后一部分可能会引起一些混乱-我会尝试重写它)非常感谢你的建议!然而,我无法做到这一点(至少不容易做到):主要问题:(1)PyYAML仅基于对象的主类决定使用哪个representer,因此添加属性persistent\u id
或使对象子类成为指定的persistent
类是行不通的;(2) 因此,representer函数无法决定是使用“交叉引用”表示法还是普通YAML表示法:这将需要告知何时作为转储另一个对象的一部分调用representer,或者“本机地”调用representer,否则我们将得到无限递归。您的代码正在输入无限递归,因为您正在调用YAML.dump(data)
在representer中,您告诉yaml.dump
使用该representer转储数据!尝试在我链接到的PyYAML文档页面中构建representer/constructor示例。具体来说,你应该在你的representer中使用dumper.representation\u scalar
而不是yaml.dump
,在你的构造函数中使用loader.construct\u scalar
而不是yaml.load
。是的,我知道它为什么会进入无限递归。关键是我不能使用表示标量
/构造标量
函数,因为“持久化”对象不是简单的标量,它们是Python对象,我必须获得“常规”YAML表示。这就是pickle的persistent_id
所做的:它生成正常的pickle表示,但将其保存到另一个文件中。我明白了,您想再次yaml.dump
对象,但不进行特殊处理,并将其保存到一个文件中,对吗?如果是这样的话,对pickle做同样的事情会不会有同样的问题?您是如何在基于pickle的解决方案中克服此问题的?是的,正确。在基于泡菜的解决方案中,我没有做任何特殊的魔法;这是泡菜的一个特点,有文献记载。