weakrefs and bound methods

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Mon Oct 8 05:28:24 CEST 2007

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):

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?

> 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. 
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.


More information about the Python-list mailing list