Альтернативы pickles `persistent_id`? - PullRequest
5 голосов
/ 29 октября 2011

Я использовал Python pickle модуль для реализации тонкого файлового персистентного слоя. слой постоянства (часть большей библиотеки) в значительной степени опирается на функцию persistent_id для pickle сохранить объекты указанных классов в виде отдельных файлов.

Единственная проблема с этим подходом заключается в том, что файлы рассола не являются редактируемые, и я бы предпочел сохранить объекты в формате, который удобочитаемый и редактируемый человеком с помощью текстового редактора (например, YAML или JSON).

Знаете ли вы о какой-либо библиотеке, которая использует редактируемый человеком формат и предлагает функции, похожие на рассол 'persistent_id? С другой стороны, есть ли у вас предложения по их реализации поверх YAML- или Основанная на JSON библиотека сериализации, без переписывания большого подмножества рассол

1 Ответ

4 голосов
/ 03 ноября 2011

Я еще не пробовал это сам, но я думаю, что вы могли бы сделать это элегантно с PyYAML , используя то, что они называют "представителями" и "распознавателями" .

РЕДАКТИРОВАТЬ

После обширного обмена комментариями с постером, вот метод для достижения требуемого поведения с PyYAML.

ВажноПримечание: Если экземпляр Persistable имеет другой такой экземпляр в качестве атрибута или каким-либо образом содержится внутри одного из его атрибутов, то содержащийся экземпляр Persistable не будет сохранен в еще одном отдельном файле, скорее он будет сохраненвстроенный в тот же файл, что и родительский экземпляр Persistable.Насколько я понимаю, это ограничение также существовало в системе OP, основанной на рассоле, и может быть приемлемым для его / ее случаев использования.Я не нашел элегантного решения для этого, которое не включает взлом 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_dump вместо yaml.dump, когда вы хотите сохранить экземпляры Persistable класс для разделения файлов.Но не используйте его внутри persistable_representer и persistable_constructor!Никакой специальной функции загрузки не требуется, просто используйте yaml.load.

Фу, это заняло некоторую работу ... Надеюсь, это поможет!

...