[Python-Dev] Pickling instances of nested classes
Walter Dörwald
walter at livinglogic.de
Fri Apr 1 13:17:24 CEST 2005
Samuele Pedroni wrote:
>> [...]
>> And having the full name of the class available would certainly help
>> in debugging.
>
> that's probably the only plus point but the names would be confusing wrt
> modules vs. classes.
You'd propably need a different separator in repr. XIST does this:
>>> from ll.xist.ns import html
>>> html.a.Attrs.href
<attribute class ll.xist.ns.html:a.Attrs.href at 0x8319284>
> My point was that enabling reduce hooks at the metaclass level has
> propably other interesting applications, is far less complicated than
> your proposal to implement, it does not further complicate the notion of
> what happens at class creation time, and indeed avoids the
> implementation costs (for all python impls) of your proposal and still
> allows fairly generic solutions to the problem at hand because the
> solution can be formulated at the metaclass level.
Pickling classes like objects (i.e. by using the pickling methods in
their (meta-)classes) solves only the second part of the problem:
Finding the nested classes in the module on unpickling. The other
problem is to add additional info to the inner class, which gets pickled
and makes it findable on unpickling.
> If pickle.py is patched along these lines [*] (strawman impl, not much
> tested but test_pickle.py still passes, needs further work to support
> __reduce_ex__ and cPickle would need similar changes) then this example
> works:
>
>
> class HierarchMeta(type):
> """metaclass such that inner classes know their outer class, with
> pickling support"""
> def __new__(cls, name, bases, dic):
> sub = [x for x in dic.values() if isinstance(x,HierarchMeta)]
I did something similar to this in XIST, but the problem with this
approach is that in:
class Foo(Elm):
pass
class Bar(Elm):
Baz = Foo
the class Foo will get its _outer_ set to Bar although it shouldn't.
> [...]
> def __reduce__(cls):
> if hasattr(cls, '_outer_'):
> return getattr, (cls._outer_, cls.__name__)
> else:
> return cls.__name__
I like this approach: Instead of hardcoding how references to classes
are pickled (pickle the __name__), deligate it to the metaclass.
BTW, if classes and functions are pickable, why aren't modules:
>>> import urllib, cPickle
>>> cPickle.dumps(urllib.URLopener)
'curllib\nURLopener\np1\n.'
>>> cPickle.dumps(urllib.splitport)
'curllib\nsplitport\np1\n.'
>>> cPickle.dumps(urllib)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "/usr/local/lib/python2.4/copy_reg.py", line 69, in _reduce_ex
raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle module objects
We'd just have to pickle the module name.
Bye,
Walter Dörwald
More information about the Python-Dev
mailing list