[Python-Dev] How to suppress instance dict? (original) (raw)

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


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

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. :-) [David] >> 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? [Guido] > 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()) Um, you're changing the rules in the middle of the game. You said you had an empty slots.

I did. I just stuck something in there so I could verify that things were working in the expected way.

My recommendation only applied to that case. I also thought you were doing this from C, not from Python, but I may be mistaken.

You're not mistaken; Just like Python gives a productivity boost over C/C++ for ordinary programming, I find I can learn a lot more about the Python core in a short period of time by writing Python code than by writing 'C' code, so I usually try that first.

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'] Hm. I don't think that x.dict is args[2]; it's a copy, and deleting getstate from the arguments doesn't make any difference to this example.

...as I discovered...

... return x ... >>> c = mc('c', (object,), { 'slots' : ['foo'], 'getstate' : lambda self: tuple() } ) Why are you passing a getstate in? The point was getting rid of the getstate that type.new inserts.

Because I didn't understand your intention, nor did I know that the automatic getstate was responsible for generating the error message. I thought the idea was to define a getstate, which is a known way to suppress the error message, and then kill it in new. I figured that pickle was looking for getstate and when it wasn't there but slots was, rasing the exception. This may explain why I didn't see how the approach could work.

Now I understand what you meant.

>>> pickle.dumps(c()) 'ccopyreg\nreconstructor\np0\n(c_main_\nc\np1\nc_builtin_\nobject\np2\nNtp3\nRp4\n.'

especially since: >>> dir(d) == dir(c) 1 I think you have been testing something very different from what you think you did here. dir(d) == dir(c) because they both have a getstate; but d.getstate is a built-in that raises an exception, while c.getstate is the lambda you passed in.

Yeah, I found that out below.

And have you tried unpickling yet? I expect it to fail.

Nope.

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.> 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? Yes. I was assuming you'd do this at the C level. To do what I suggested in Python, I think you'd have to write this: class M(type): def new(cls, name, bases, dict): C = type.new(cls, name, bases, dict) del C.getstate return C

I tried to get too fancy with del C.dict['getstate'] which didn't work of course. Anyway, thanks for spelling it out for me. I think I understand everything now.

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