strange error whilst porting to 2.6
Robin Becker
robin at reportlab.com
Mon Jan 26 10:45:25 EST 2009
Robin Becker wrote:
> I found that this error
>
>> Exception RuntimeError: 'maximum recursion depth exceeded in
>> __subclasscheck__' in <type 'exceptions.AttributeError'> ignored
>
> occurs when attempting to copy (copy.copy(inst)) an instance of a class
> that looks like this
>
> class LazyParagraph(_LazyMixin,TTParagraph):
> SUPER=TTParagraph
> _CLEAN_SPACE=1
........
>
> I have attempted to abstract the problem, but so far I haven't found the
> vital bits.
OK this turns out to be one of those useful exercises after all. After
instrumenting the copy instance copy func my colleague and I found the problem
occurs in this innocuous looking example
###################
import copy
class _LazyMixin:
"""don't do any initialization until later"""
def __init__(self,*args):
self._args = args
self._initialized = 0
def __getattr__(self,a):
if not self._initialized:
self._Initialize()
return getattr(self,a)
raise AttributeError("No attribute '%s'" % a)
def _Initialize(self):
if not self._initialized:
self._initialized = 1
del self._args
l=_LazyMixin()
print l._initialized
copy.debug=1
copy.copy(l)
###################
it turns out that in the absence of other info _copy_inst creates a dummy
instance and changes its class to the incoming class. It then asks the new
unpopulated instance if it has an attribute __setstate__, that triggers the
_LazyMixin __getattr__ which fails because there's no _initialize member so
__getattr__ gets recalled etc etc. Presumably in earlier pythons this bad
behaviour is just hidden. The fix for us is to provide a __setstate__ which does
what the no __setstate__ code does ie update __dict__.
However, since the _copy_inst code knows there can be no members on the new
instance should it not be asking the __class__ for __setstate__?
--
Robin Becker
More information about the Python-list
mailing list