Weakref.ref callbacks and eliminating __del__ methods

Tim Peters tim.peters at gmail.com
Mon Jan 24 14:37:45 EST 2005


[Tim]
>> I'll note that one fairly obvious pattern works very well for weakrefs
>> and __del__ methods (mutatis mutandis):  don't put the __del__ method
>> in self, put it in a dead-simple object hanging *off* of self.  Like
>> the simple:
>>
>> class BTreeCloser:
>>     def __init__(self, btree):
>>         self.btree = btree
>>
>>     def __del__(self):
>>         if self.btree:
>>             self.btree.close()
>>             self.btree = None
>>
>> Then give self an attribute refererring to a BTreeCloser instance, and
>> keep self's class free of a __del__ method.  The operational
>> definition of "dead simple" is "may or may not be reachable only from
>> cycles, but is never itself part of a cycle".

[Richie Hindle]
> This is very nice - I've been wondering about just this problem recently,
> and this will be very useful.  Many thanks!

Thank me if it's *actually* useful <0.5 wink>:  depending on
everything, it may leave problems anyway, including that there's no
100% guarantee that a __del__ method will ever get called, and that
__del__ methods (weakref callbacks too, for that matter) triggered
while Python is tearing itself down at exit may suffer bizarre
exceptions (due to trying to use facilities in partially-torn down
modules, including the module the __del__ method appears in).

For those reasons, it's best practice to release critical resources
explicitly.  __del__ is more a crutch than a limousine.

> One question: why the `self.btree = None` in the last line?  Isn't
> `self.btree` guaranteed to go away at this point anyway?  (If the answer
> is "it's necessary for weird cases that would take an hour to explain"
> then I'll be more than happy to simply use it.  8-)

Here, it was mostly just copy+paste from Mike's original example.  In
general, __del__ is a user-visible method like any other, and user
code may call it explicitly.  For that reason, it's safest to write
__del__ methods in library objects such that they can be invoked
multiple times gracefully.  I think the nicest way to do that is along
the lines Mike later showed:  write a close()-like method to release
resource explicitly (although naming it __call__ seems dubious),
ensure close() is idempotent, and then write a one-liner __del__:

    def close(self):
        yadda
        yadda
        yadda

    def __del__(self):
        self.close()

If you're writing code for your own use, and know __del__ will never
be called explicitly, and know your __del__ can't resurrect self, then
"`self.btree` [is] guaranteed to go away at this point" is true, and
you can ignore all this safely.



More information about the Python-list mailing list