为什么我的弱引用在指向一个方法时却死在了水里?

发布于 2024-10-24 12:18:12 字数 1716 浏览 2 评论 0原文

可能的重复:
为什么弱引用在此绑定方法上不起作用?

我在观察者模式中使用弱引用,并注意到一个有趣的现象。如果我创建一个对象并将其方法之一添加为 Observable 的观察者,则引用几乎立即失效。谁能解释发生了什么?

我也对为什么这可能是一个坏主意感兴趣。我决定不使用weakrefs,只是确保使用Observable.removeobserver 正确清理自己,但我的好奇心在这里杀死了我。

这是代码:

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)

这是输出:

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

主要要注意的是,调用 addobserver 之后的 print 语句显示weakref 已经死了。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凡间太子 2024-10-31 12:18:12

每当您引用对象方法时,就会发生一些神奇的事情,而正是这种神奇的情况阻碍了您。

具体来说,Python 查找对象类上的方法,然后将其与对象本身结合起来创建一种称为绑定方法的可调用方法。例如,每次计算表达式self.foo 时,都会创建一个新的绑定方法实例。如果您立即对此进行弱引用,那么就没有对绑定方法的其他引用(即使对象和类的方法仍然具有实时引用)并且弱引用将消失。

有关解决方法,请参阅ActiveState 上的此代码段

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.

谷夏 2024-10-31 12:18:12

每次访问实例 obj.m 的方法时,都会生成一个可调用的包装器(称为“绑定方法”)并添加 self (obj< /code>) 作为调用时的第一个参数。这是“隐式”传递 self 的一个巧妙的解决方案,并且允许首先传递实例方法。但这也意味着每次输入 obj.m 时,都会创建一个新的(非常轻量级的)对象,除非您保留对它的(非弱)引用,否则它将被 GC' d,因为没有人会为你保留它。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文