On Tue, Apr 30, 2013 at 2:49 AM, MRAB
How about this:
If an object has a __collect__ method, then that method will be called whenever the object is collected...
It should be noted that the method could be called more than once.
Interesting. Adds complication (splitting __del__ into two functions __del__ and __collect__), where one of them might be called more than once. But that complication is now contained entirely within the class that needs it.
def __del__(self): self.__collect__() # Implicit or explicit? print("Deleting node %s" % self.payload) def __collect__(self): print("Collecting node % s" % self.payload) if self.prev is None: # Already broken the cycle. print("Already collected %s" % self.payload) return
self.prev.next = self.next self.next.prev = self.prev
# Break the cycle. self.prev = self.next = None
Hmm. There's no guarantee that, once __collect__ is called, __del__ and deallocation will shortly follow. There might be a refloop created externally, somewhere. So there is the possibility that this object will have methods called after __collect__ is called, meaning those methods - ergo *all* methods - will have to deal with the possibility that the invariants are broken. And if I change that last line to "self.prev = self.next = self" (which would disconnect it from its chain and leave it as a stand-alone list of its own - as per __init__), the garbage hangs around. I'd rather, if possible, be able to guarantee that the object's invariants are always true (aside from deliberate fiddling and breaking from external code), rather than having the exception that "once the gc tries to dispose of you once, you're broken".
def callback(phase, info): if phase == "stop": new_garbage = []
for obj in gc.garbage: if hasattr(obj, "__collect__"): obj.__collect__() else: new_garbage.append(obj)
gc.garbage[:] = new_garbage
import gc gc.callbacks.append(callback)
Aside: I do like the way this can be implemented in pure Python. Ever so much easier to POC than throwing patch files around! ChrisA