[Python-Dev] Re: [Python-checkins]python/dist/src/Modules gcmodule.c,,

Tim Peters tim_one@email.msn.com
Sat, 5 Apr 2003 14:34:36 -0500

I checked in some more changes (2.3 head only).  This kind of program may be

class C:
    def __getattr__(self, attribute):
        global alist
        if 'attr' in self.__dict__:
            del self.attr
        raise AttributeError

import gc
a = C()
b = C()
alist = []
a.attr = b
b.attr = a
a.x = 1
b.x = 2

del a, b

# Oops.  This prints 4:  it's collecting
# a, b, and their dicts.
print gc.collect()

# Despite that __getattr__ resurrected them.
print alist

# But gc cleared their dicts.
print alist[0].__dict__
print alist[1].__dict__

# So a.x and b.x fail.
print alist[0].x, alist[1].x

While a __getattr__ side effect may resurrect an object in gc's unreachable
list, gc has no way to know that an object has been resurrected short of
starting over again.  In the absence of that, the object remains in gc's
unreachable list, and its tp_clear slot eventually gets called.  The
internal C stuff remains self-consistent, so this won't cause a segfault
(etc), but it may (as above) be surprising.  I don't see a sane way to fix
this so long as asking whether __del__ exists can execute arbitrary mounds
of Python code.