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