[Python-Dev] How to suppress instance __dict__?

David Abrahams dave@boost-consulting.com
Sun, 23 Mar 2003 09:48:53 -0500

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

>> I am generating extension types derived from a type which is derived
>> from int 'int' by calling the metaclass; in order to prevent instances
>> of the most-derived type from getting an instance __dict__ I am
>> putting an empty tuple in the class __dict__ as '__slots__'.  The
>> problem with this hack is that it disables pickling of these babies:
>>    "a class that defines __slots__ without defining __getstate__
>>     cannot be pickled"
>> Yes, I can define __getstate__, __setstate__, and __getinitargs__ (the
>> only one that can actually do any work, since ints are immutable),
>> but I was wondering if there's a more straightforward way to suppress
>> the instance __dict__ in the derived classes.
> Actually, even __getinitargs__ won't work, because __init__ is called
> after the object is created.  

...and ints are immutable.  Right.

> In Python 2.3, you'd use __getnewargs__,


It's almost too bad that the distinction between __new__ and __init__
is there -- as we find we need to legitimize the use of __new__ with
things like __getnewargs__ it be comes a little less clear which one
should be used, and when.  TIMTOWDI and all that.

In the absence of clear guidelines I'm tempted to suggest that C++ got
this part right.  Occasionally we get people who think they want to
call overridden virtual functions from constructors (I presume the
analogous thing could be done safely from __init__ but not from
__new__) but that's pretty rare.  I'm interested in gaining insight
into the Pythonic thinking behind __new__/__init__; I'm sure I don't
have the complete picture.

> but I expect you're still bound to supporting Python 2.2

Yup, I think it would be bad to force my users to move to an
unreleased Python version at this point ;-)

> (Python 2.3 also doesn't have the error message above when
> pickling).

Nice. Too bad about 2.2.

> 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?

Dave Abrahams
Boost Consulting