[Python-ideas] CPython's cyclic garbage collector (was Automatic context managers)
Chris Angelico
rosuav at gmail.com
Tue Apr 30 00:27:11 CEST 2013
On Tue, Apr 30, 2013 at 2:49 AM, MRAB <python at mrabarnett.plus.com> wrote:
> 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
More information about the Python-ideas
mailing list