Hi again, Guido,
No no no, I'm not fiddling around with any internals, here. I just want to use the machinary as it is, and to be able to pickle almost everything.
Sorry, this was a lie. Sure I'm fiddling internaly, but simply by installing some __reduce__ methids, hoping that they work. This worked most of the time, but I'm having problems with bound methods.
But how, I wonder, are you providing it? You can't subclass instancemethod -- how do you manage to add a __reduce__ method to it without fiddling with any internals?
I added __reduce__ to the PyMethod type and tried to figure out why it didn't take it.
My expectation is that C().x.__reduce__ gives me the bound __reduce__ method of the bound x method of a C instance.
Yes, unfortunately you get the __reduce__ method of the unbound function instead.
I think Martin is right: copy_reg may be your last hope. (Or subclassing pickle to special-case instancemethod.)
Well, I see your point, but please let me explain mine, again: If there is a class C which has a method x, then C().x is a perfectly fine expression, yielding a bound method.
If I now like to pickle this expression, I would use the __reduce__ protocol and ask C().x for its __reduce__ property.
Now, please see that __reduce__ has no parameters, i.e. it has no other chance to do the right thing(TM) but by relying on to be bound to the right thing. So, doesn't it make sense to have __reduce__ to be always returned as a method of some bound anything?
In other words, shouldn't things that are only useful as bound things, always be bound?
The pickling machinery wasn't intended to pickle bound methods or functions etc., and doesn't particularly go out of its way to allow you to add that functionality.
The pickling machinery gives me an __reduce__ interface, and I'm expecting that this is able to pickle everything.
And it would be except for the delegation of method attributes to function attributes. It is a similar aliasing problem as you see when you try to access the __getattr__ implementation for classes as C.__getattr__ -- you get the __getattr__ for C instances instead. So you have to use type(C).__getattr__ instead. That would work for __reduce__ too I think: new.instancemethod.__reduce__(C().f).
I agree! But I can't do this in this context, using __reduce__ only. In other words, I'd have to add stuff to copyreg.py, which I tried to circumvent.
OK, so you *are* messing with internals after all (== changing C code), right? Or else how do you accomplish this?
Yessir, I'm augmenting all things-to-be-pickled with __reduce__ methods. And this time is the first time that it doesn't work.
I have a real job too, that's why I have little time to help you. :-(
I agree (and I didn't ask *you* in the first place), but still I'd like to ask the general question: Is this really the right way to handle bound objects? Is the is_data criterion correct? If I am asking for an attribute that makes *only* sense if it is bound, like in the parameter-less __reduce__ case, wouldn't it be the correct behavior to give me that bound object?
I have the strong impression that there is some difference in methods which isn't dealt with, correctly, at the moment. If a method wants to be bound to something, it should be get bound to something. Especially, if this method is useless without being bound. Please, swallow this idea a little bit, before rejecting it. I think that "is_data" is too rough and doesn't fit the requirements, all the time.
sincerely -- chris