开发者

why are my weakrefs dead in the water when they point to a method? [duplicate]

This question already has answers here: Closed 10 years ago.

Possible Duplicate:

Why doesn't the weakref work on this bound method?

I'm using weakrefs in an observer-pattern and noticed an interesting phenomenon. If I create an object and add one of it's methods as an observer of an Observable, the reference is dead almost instantly. Can anyone explain what is happening?

I'm also interested in thoughts for why this might be a bad idea. I've decided not to use the weakrefs and just make sure to clean up after myself properly with Observable.removeobserver, but my curiosity is killing me here.

Here's the code:

from weakref import ref
class Observable:
    __observers = None
    def addobserver(self, observer):
        if not self.__observers:
            self.__observers = []
        self.__observers.append(ref(observer))
        print 'ADDING observer', ref(observer)

    def removeobserver(self, observer):
        self.__observers.remove(ref(observer))

    def notify(self, event):
        for o in self.__observers:
            if o() is None:
                print 'observer was deleted (removing)', o
                self.__observers.remove(o)
            else:
                o()(event)

class C(Observable):
    def set(self, val):
        self.notify(val)

class bar(object):
    def __init__(self):
        self.c = C()
        self.c.addobserver(self.foo)
        print self.c._Observable__observers

开发者_运维知识库    def foo(self, x):
        print 'callback', x  #never reached

b = bar()
b.c.set(3)

and here's the output:

ADDING observer <weakref at 0xaf1570; to 'instancemethod' at 0xa106c0 (foo)>
[<weakref at 0xaf1570; dead>]
observer was deleted (removing) <weakref at 0xaf1570; dead>

the main thing to note is that the print statement after the call to addobserver shows that the weakref is already dead.


Whenever you do reference an object method, there's a bit of magic that happens, and it's that magic that's getting in your way.

Specifically, Python looks up the method on the object's class, then combines it with the object itself to create a kind of callable called a bound method. Every time e.g. the expression self.foo is evaluated, a new bound method instance is created. If you immediately take a weakref to that, then there are no other references to the bound method (even though both the object and the class's method still have live refs) and the weakref dies.

See this snippet on ActiveState for a workaround.


Each time you access a method of an instance, obj.m, a wrapper (called "bound method" is generated) that's callable an adds self (obj) as first argument when called. This is a neat solution for passing self "implicitly" and allows passing instance methods in the first place. But it also means that each time you type obj.m, a new (very lightweight) object is created, and unless you keep a (non-weak) reference to it around, it will be GC'd, because nobody will keep it alive for you.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜