pickle 的 `persistent_id` 的替代品?

发布于 2024-12-13 05:34:58 字数 537 浏览 1 评论 0原文

我一直在使用Python的 pickle 用于实现基于文件的薄持久层的模块。这 持久层(较大库的一部分)严重依赖pickle的 persist_id 功能 将指定类的对象保存为单独的文件。

这种方法的唯一问题是 pickle 文件不是人类的 可编辑,而且我更愿意以以下格式保存对象 人类可以使用文本编辑器读取和编辑(例如,YAML 或 JSON)。

您是否知道任何使用人工可编辑格式的库 提供与picklepersistent_id 类似的功能吗?或者, 您对在 YAML 或 YAML 之上实现它们有什么建议吗? 基于 JSON 的序列化库,无需重写大部分子集 泡菜

I have been using Python's pickle
module for implementing a thin file-based persistence layer. The
persistence layer (part of a larger library) relies heavily on pickle's persistent_id feature
to save objects of specified classes as separate files.

The only issue with this approach is that pickle files are not human
editable, and I'd much rather have objects saved in a format that is
human readable and editable with a text editor (e.g., YAML or JSON).

Do you know of any library that uses a human-editable format and
offers features similar to pickle's persistent_id? Alternatively,
do you have suggestions for implementing them on top of a YAML- or
JSON-based serialization library, without rewriting a large subset of
pickle?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

糖果控 2024-12-20 05:34:58

我自己还没有尝试过,但我认为您应该能够使用 PyYAML 优雅地完成此操作他们称之为“代表者”和“解析器”

编辑

在与发布者广泛交换意见后,这里是一种使用 PyYAML 实现所需行为的方法。

重要提示:如果 Persistable 实例具有另一个此类实例作为属性,或者以某种方式包含在其属性之一内,则所包含的 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)

从现在开始,当您想要将 Persistable 类的实例保存到单独的文件时,请使用 my_yaml_dump 而不是 yaml.dump。但是不要persistable_representerpersistable_constructor内部使用它!不需要特殊的加载函数,只需使用yaml.load即可。

唷,这需要一些工作......我希望这会有所帮助!

I haven't tried this yet myself, but I think you should be able to do this elegantly with PyYAML using what they call "representers" and "resolvers".

EDIT

After an extensive exchange of comments with the poster, here is a method to achieve the required behavior with PyYAML.

Important Note: If a Persistable instance has another such instance as an attribute, or contained somehow inside one of its attributes, then the contained Persistable instance will not be saved to yet another separate file, rather it will be saved inline in the same file as the parent Persistable instance. To the best of my understanding, this limitation also existed in the OP's pickle-based system, and may be acceptable for his/her use cases. I haven't found an elegant solution for this which doesn't involve hacking 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)

From now on use my_yaml_dump instead of yaml.dump when you want to save instances of the Persistable class to separate files. But don't use it inside persistable_representer and persistable_constructor! No special loading function is necessary, just use yaml.load.

Phew, that took some work... I hope this helps!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文