Alternatives to pickle's `persistent_id`?
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 yamlfrom functools import partialclass 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): passPersistingDumper.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 valueyaml.add_constructor(u'!xref', persistable_constructor)# example use, also serves as a testclass 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_fooprint yaml.load(dumped_foo)print yaml.load(dumped_foo).oneprint "=== bar ==="dumped_bar = my_yaml_dump(bar)print dumped_barprint yaml.load(dumped_bar)print yaml.load(dumped_bar).fooprint yaml.load(dumped_bar).foo.onebaz = Bar(Persistable())print "=== baz ==="dumped_baz = my_yaml_dump(baz)print dumped_bazprint 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!