[Python-Dev] How to suppress instance __dict__?

David Abrahams dave@boost-consulting.com
Sun, 23 Mar 2003 11:41:17 -0500


Guido van Rossum <guido@python.org> writes:

>> > I think you could subclass the metaclass, override __new__, and delete
>> > the bogus __getstate__ from the type's __dict__.  Then you'll get the
>> > default pickling behavior which ignores slots; that should work just
>> > fine in your case. :-)
>> 
>> Ooh, that's sneaky!  But I can't quite see how it works.  The error
>> message I quoted at the top about __getstate__ happens when you try to
>> pickle an instance of the class.  If I delete __getstate__ during
>> __new__, it won't be there for pickle to find when I try to do the
>> pickling.  What will keep it from inducing the same error?
>
> Just try it.  There are many ways to customize pickling, and if
> __getstate__ doesn't exist, pickling is done differently.

Since this doesn't work:

    >>> d = type('d', (object,), { '__slots__' : ['foo'] } )
    >>> pickle.dumps(d())

I'm still baffled as to why this works:

    >>> class mc(type):
    ...     def __new__(self, *args):
    ...             x = type.__new__(self, *args)
    ...             del args[2]['__getstate__']
    ...             return x
    ...
    >>> c = mc('c', (object,), { '__slots__' : ['foo'], '__getstate__' : lambda self: tuple() } )
    >>> pickle.dumps(c())
    'ccopy_reg\n_reconstructor\np0\n(c__main__\nc\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n.'

especially since:

    >>> dir(d) == dir(c)
    1

I don't see the logic in the source for object.__reduce__(), so where
is it?  OK, I see it in typeobject.c.  But now:

    >>> c.__getstate__
    <unbound method c.<lambda>>

OK, this seems to indicate that my attempt to remove __getstate__ from
the class __dict__ was a failure.  That explains why pickling c works,
but not why you suggested that I remove __getstate__ inside of
__new__.  Did you mean for me to do something different?

I note that c's __slots__ aren't pickled at all, which I guess was the
point of the __getstate__ requirement:

    >>> x = c()
    >>> x.foo = 1
    >>> pickle.dumps(x) == pickle.dumps(c())
    1

Fortunately, in our case the __slots__ are empty so it doesn't matter.

-- 
Dave Abrahams
Boost Consulting
www.boost-consulting.com