Message20449
Logged In: YES
user_id=63133
This infinite recursion also occurs in another place, that
got me stumped for a couple of days when old code that
worked with Python 2.2 stopped working. If __class__ is not
fidgeted with (as in original bug report), but a descriptor
returns a custom reduce for the class, but not for its
objects, reduce enters an infinite loop on the object:
"""
class descriptor_for_reduce(object):
def __get__(self,obj,tp=None):
if obj is not None: return
super(ASpecialClass,obj).__reduce__
return self.reducer
def reducer(self,proto=None):
return "VerySpecial"
class ASpecialClass(object):
__reduce__ = descriptor_for_reduce()
copy.copy(ASpecialClass())
"""
ASpecialClass().__reduce__ is object.__reduce__, which is
implemented by typeobject.c:object_reduce_ex. This function
(that doesn't know if its called as the __reduce__ or the
__reduce_ex__ method) tries to detect if the object's
__reduce__ is overridden. It does so by checking if the
object's class's __reduce__ is overridden, and in fact it
is. It then assumes that the object's __reduce__ is
overridden, and calls it. But the object's __reduce__ is
the same function, causing the infinite loop.
If __reduce_ex__ is used instead of __reduce__, the problem
goes away, ASpecialClass().__reduce_ex__() return the usual
tuple, and ASpecialClass.__reduce_ex__() return
"VerySpecial". But when __reduce__ is overridden,
ASpecialClass().__reduce__() enters an infinite loop.
I believe this is a legitimate example that should behave
just as when __reduce_ex__ is overridden. The example
doesn't lie about __class__, and it is certainly legitimate
for define a property that behaves differently for the class
and for its objects.
Where did this come up and why would I ever care about a
class's __reduce__? The __reduce__ attribute of a class is
never used by (the standard) pickle or copy, since
save_global() is called instead. However, I have a custom
pickler, implemented as a subclass of pickle.Pickler, which
falls back on the class's __reduce__ when save_global()
fails. This way, I can pickle certain classes that are
created at run-time (and can be easily recreated, e.g. from
their bases and dictionaries).
|
|
| Date |
User |
Action |
Args |
| 2007-08-23 14:20:51 | admin | link | issue931877 messages |
| 2007-08-23 14:20:51 | admin | create | |
|