One Python 2.1 idea

Tim Peters at
Wed Dec 27 03:30:36 EST 2000

> Note:
> >>> class Oops:
>         def foo(self):
>             pass
> >>> x = Oops()
> >>> =
> >>> is x
> 1
> >>>
> Oops!  That is, x is now involved in a reference cycle (x's
> dict contains a bound method that points back to x).  Before 2.0,
> that's a memory leak.  In 2.0, it's a leak only if the class
> (unlike Oops above) has a __del__ method (or you've disabled
> cyclic gc).

[Darrell Gallion]
> You lost me here Tim.
> ...
> Don't see what's changed after a.f=a.f

The right-hand side a.f found Oops.__dict__['f'], and made a bound method
object out of it and a.  The left-hand side a.f makes that bound method the
value of a.__dict__['f'] (not in Oops's dict again, but in a's dict!).  So
what changed is that a.__dict__.has_key('f') was false before "a.f = a.f",
but is true after.  And a.__dict__['f'].im_self is a.

Why you changed all the names from the orginal example isn't clear or
helpful, so I'll add a few lines to the original instead:

>>> class Oops:
        def foo(self): pass

>>> x = Oops()
>>> x.__dict__ # the instance dict is empty at the start
>>> =  # but this puts something into it
>>> x.__dict__
{'foo': <method of Oops instance at 00B24FDC>}
>>> x.__dict__['foo'].im_self is x  # this is the cycle
>>> Oops.__dict__['foo']  # in Oops's dict, it's just a function
<function foo at 00B1E6FC>
>>>  # but accessing a class dict via attr notation does magic
<unbound method>

This is pretty deep magic!  Don't go doing things like "a.f=a.f", and you
can safely ignore it for decades.

and-writing-"x=x"-can-erase-your-hard-drive<wink>-ly y'rs  - tim

More information about the Python-list mailing list