weakrefs and bound methods

Michele Simionato michele.simionato at gmail.com
Mon Oct 8 00:06:55 EDT 2007


On Oct 7, 11:28 pm, Steven D'Aprano
<ste... at REMOVE.THIS.cybersource.com.au> wrote:
> On Sun, 07 Oct 2007 12:55:29 -0700, Alex Martelli wrote:
> >> What should I do when my objects need to perform some special
> >> processing when they are freed, if I shouldn't use __del__?
>
> > The solid, reliable way is:
>
> > from __future__ import with_statement
>
> > and use module contextlib from the Python standard library (or handcode
> > an __exit__ method, but that's rarely needed), generating these special
> > objects that require special processing only in 'with' statements.  This
> > "resource acquisition is initialization" (RAII) pattern is the RIGHT way
> > to ensure timely finalization (particularly but not exclusively in
> > garbage-collected languages, and particularly but not exclusively to
> > ease portability to different garbage collection strategies -- e.g.,
> > among CPython and future versions of IronPython and/or Jython that will
> > support the with statement).
>
> Hmmm... I'm not sure I understand how a with statement is meant to
> replace class.__del__ in practice. It seems to me that the two things
> have different uses. with is useful when you create an object, do
> something with it, dispose of it in an orderly fashion, and then
> continue. How does that help when you create an unknown number of long-
> lasting objects where you can't predict how and when they will be
> disposed of?
>
> Here's a minimal example. I have a module that returns parrot objects:
>
> # Parrot module
> class Parrot(object):
>     def __del__(self):
>         print "I'm now pushing up the daisies"
>
> # Callers code:
> import Parrot
> p = Parrot.Parrot()
> alist = [Parrot.Parrot() for i in range(1000)]
> # do something with p and alist
> print p, alist
> # instances are deleted in arbitrary order
> del p
> del alist[3]
> del alist[853]
> del alist[701]
> del alist
>
> It seems to me that you are saying to re-write the above as something
> like this:
>
> # Parrot module
> class Parrot(object):
>     pass
>
> class killed(object): # context manager
>     def __exit__(self, *exc_info):
>         print "I'm now pushing up the daisies"
>
> # Callers code:
> import Parrot
> with killed(Parrot.Parrot()) as p:
>     # ... er, what do I do with alist???
>     # do arbitrary stuff with p and alist
>     print p, alist
>
> Now, I don't think the above is feasible. What am I missing?

Rename your __del__ to close and call it explicitely:

p.close()
alist[3].close()
alist[853].close()
alist[701].close()

> > An alternative that will work in pre-2.5 Python (and, I believe but I'm
> > not sure, in Jython and IronPython _today_) is to rely on the weakref
> > module of the standard Python library.
>
> ...
>
> I'm going to need some time to play around with that, but it seems
> reasonably straightforward. But the obvious thing I can see is that
> there's an awful lot of boilerplate code that needs to be written for
> each and every class that needs a "weak finalizer".
>
> That is to say, Python "guarantees" that __del__ will always be called
> (unless it isn't... "guarantee void on planet Earth") for your objects,
> so the developer doesn't need to do anything except write the finalizer.

Yep, the problem is that __del__ does NOT guarantee anything.
So, it *looks* easy, but it is actually very fragile and in
subtle cases can betray you without telling. I, for one,
I don't like to have bombs in my code waiting to explode
at some unknown moment ...

> To do the right thing with weakrefs means that not only does the
> developer have to write the finalizer, but he has to write the code to
> ensure the finalizer is called. I'm not sure that's a step forward.

Yep, we would need a better support for finalizers in the
standard library. For the moment, there are various recipes
in the Python cookbook. See also this post:
http://groups.google.com/group/comp.lang.python/browse_frm/thread/b09e02b7c67c8a3b/1ef0f64bb539cfb0?hl=en&lnk=gst&q=simionato+__del__&rnum=1#1ef0f64bb539cfb0




More information about the Python-list mailing list