[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. -- http://mail.python.org/mailman/listinfo/python-list