weakrefs and bound methods

Michele Simionato michele.simionato at gmail.com
Sun Oct 7 13:34:51 EDT 2007


On Oct 7, 1:14 pm, Steven D'Aprano <st... at REMOVE-THIS-
cybersource.com.au> wrote:
> On Sun, 07 Oct 2007 16:38:23 +0000, Michele Simionato wrote:
> > On Oct 7, 12:26 pm, Marc 'BlackJack' Rintsch <bj_... at gmx.net> wrote:
>
> >> Drop all those `__del__()` methods as they prevent the garbage
> >> collector from collecting "cycles".
>
> > I fully agree and I will add that __del__ methods are always a bad idea.
>
> Always?
>
> I recently wrote a bit of code where I needed to check that releasing the
> first object in a tree-like structure would allow Python to garbage
> collect all the other objects in a tree. I thought it would, but I wanted
> to be sure ("don't guess, test"), so I wrote a simple class, gave it a
> __del__ method that just printed self, inserted them in the tree, and
> then deleted the first one.
>
> Worked like a charm.
>
> Without __del__, what should I have done to test that my code was
> deleting objects and not leaking memory?
>
> What should I do when my objects need to perform some special processing
> when they are freed, if I shouldn't use __del__?

The best thing is to use explicit resource management,
for instance with a try .. finally or with the "with" statement
in Python 2.5. The next best thing is to use weak references.
I have some code for various experiments with wearefs I did
some time ago, here it is:

import itertools, weakref, sys, gc

reference_list = [] # cannot be a set, you would lose references
resource_counter = itertools.count(1)

def resource(before_closing_callback=None,
after_closing_callback=None):
    private = '_resource_%s' % resource_counter.next()

    def get(self):
        return getattr(self, private)

    def set(self, resource):
        setattr(self, private, resource)
        def close(ref):
            if before_closing_callback:
                before_closing_callback(resource)
            resource.close()
            if after_closing_callback:
                after_closing_callback(resource)
            reference_list.remove(ref)
        reference_list.append(weakref.ref(self, close))

    return property(get, set)

class FakeResource(object):
    def __init__(self, name):
        print 'opening resource %s' % name
        self.name = name
    def close(self):
        print 'closing resource %s' % self.name
    def __repr__(self):
        return '<FakeResource %r>' % self.name

class Example(object):
    def __init__(self):
        self.resource1 = FakeResource('r1')
        self.resource2 = FakeResource('r2')
    def __del__(self):
        print '**************'
        self.resource1.close()
        self.resource2.close()

def warn_before_closing(res):
    sys.stdout.write('going to close %s\n' % res)

class Example2(object):

    resource1 = resource(warn_before_closing)
    resource2 = resource()

    def __init__(self):
        self.resource1 = FakeResource('r1')
        self.resource2 = FakeResource('r2')


gc.set_debug(gc.DEBUG_LEAK)

#e = Example()
e = Example2()
e.e = e
del e
print reference_list






More information about the Python-list mailing list