Duncan Booth
2/19/2008 1:26:00 PM
Nick Craig-Wood <nick@craig-wood.com> wrote:
> [<__main__.Y object at 0xb7d9fc8c>, <__main__.Y object at 0xb7d9fcac>,
> <__main__.Y object at 0xb7d9fc2c>] [<__main__.Y object at 0xb7d9fc8c>]
>
> (It behaves slightly differently in the interactive interpreter for
> reasons I don't understand - so save it to a file and try it!)
Any expression in the interactive interpreter is implicitly assigned to
the variable '_', so after your first call to Y.list() you've saved
references to the complete list in _. Assignments aren't expressions so
after assigning to a and c you haven't changed _. If you throw in
another unrelated expression you'll be fine:
>>> a = Y()
>>> b = Y()
>>> c = Y()
>>> Y.list()
[<__main__.Y object at 0x0117F230>, <__main__.Y object at 0x0117F2B0>,
<__main__.Y object at 0x0117F210>, <__main__.Y object at 0x0117F670>,
<__main__.Y object at 0x0117F690>, <__main__.Y object at 0x0117F6B0>,
<__main__.Y object at 0x0117F310>]
>>> a = 1
>>> c = 1
>>> c
1
>>> Y.list()
[<__main__.Y object at 0x0117F6B0>]
> In fact I find most of the times I wanted __del__ can be fixed by
> using a weakref.WeakValueDictionary or weakref.WeakKeyDictionary for a
> much better result.
The WeakValueDictionary is especially good when you want a Python
wrapper round some external non-python thing, just use the address of
the external thing as the key for the dictionary and you can avoid
having duplicate Python objects.
The other option for classes involved in a cycle is to move the __del__
(and anything it needs) down to another class which isn't part of the
cycle, so the original example becomes:
>>> class Monitor(object):
def __del__(self): print "gone"
>>> class X(object):
def __init__(self):
self._mon = Monitor()
>>> a = X()
>>> a = 1
gone
>>> b = X()
>>> b.someslot = b
>>> b = 1
>>> import gc
>>> gc.collect()
gone
8
>>>