Weak link callback not called due to circular references

I am trying to write a finalizer for Python classes that have circular references. I found out that weak callbacks are a way . Unfortunately, it seems that I use lambda, since the callback is never called. For example, by running this code:

def del_A(name):
    print('An A deleted:' + name)

class A(object):
    def __init__(self, name):
        print('A created')
        self.name = name
        self._wr = weakref.ref(self, lambda wr, n = self.name: del_A(n))

class B(object):
    def __init__(self):
        print('B created')

if __name__ == '__main__':
    a = A('a1')
    b = B()
    a.other = b
    b.other = a

returns:

A created
B created

Removing a circular reference makes the lambda callback work ("AA deleted: a1" printed). Replacing a lambda with a simple function call also works, but the parameter value is fixed when the weak link is initialized, and not when the callback is called:

self._wr = weakref.ref(self, del_A(self.name))
...
a = A('a1')
a.name = 'a2'
b = B()
a.other = b
b.other = a

returns:

A created
An A deleted:a1
B created

Any idea why lambda callback doesn't work with circular links?

+3
3

, , :

, " weakref , "

, , A , . - (.. ) . :

def del_A(name):
    print('An A deleted:' + name)

class A(object):
    def __init__(self, name, finalizers):
        print('A created')
        self.name = name
        finalizers.append(weakref.ref(self, lambda wr, n = self.name: del_A(n)))

class B(object):
    def __init__(self):
        print('B created')

def do_work(finalizers):
    a = A('a1', finalizers)
    b = B()
    a.other = b
    b.other = a

if __name__ == '__main__':
    finalizers = []
    do_work(finalizers)

:

A created
B created
An A deleted:a1

, do_work() , , . , , , .

+2

 self._wr = weakref.ref(self, lambda wr, n = self.name: del_A(n))  

self.

, , ,

a = A('a1')
b = B()
a.other = b   # This gives a another attribute; it does not switch `a` away from the original `a`
b.other = a

a. a .

,

a = A('a1')
b = B()
a = b
b = a

self._wr = weakref.ref(self, del_A(self.name))

None. del_A(self.name) , . , del_A(self.name) An A deleted:a1 ( , a1 ) None, weakref.

+2

. , , __del__.

__del__

0

Source: https://habr.com/ru/post/1733512/


All Articles