如果我在Python中引用了一个绑定方法,那么单独保持对象存活吗?

Ben*_*Ben 8 python matplotlib

我今天写了这样的东西(与mpl_connect文档不同:

class Foo(object):
    def __init__(self): print 'init Foo', self
    def __del__(self): print 'del Foo', self
    def callback(self, event=None): print 'Foo.callback', self, event


from pylab import *
fig = figure()
plot(randn(10))
cid = fig.canvas.mpl_connect('button_press_event', Foo().callback)
show()
Run Code Online (Sandbox Code Playgroud)

这看起来很合理,但它不起作用 - 就好像matplotlib失去了我给它的功能.如果不通过它Foo().callback我通过它lambda e: Foo().callback(e),它的工作原理.同样,如果我说x = Foo(),然后通过它x.callback,它的工作原理.

我的假设是,创建的未命名的Foo实例会在行Foo()之后立即销毁mpl_connect- 具有Foo.callback引用的matplotlib 不会保持Foo活动状态.那是对的吗?

在我遇到的非玩具代码中,解决方案x = Foo()没有用,大概是因为在那种情况下show()其他地方x已经超出了范围.

更一般地说,Foo().callback是一个<bound method Foo.callback of <__main__.Foo object at 0x03B37890>>.我的主要惊喜是,似乎绑定方法实际上并没有保持对对象的引用.那是对的吗?

Tim*_*ers 5

是的,绑定方法引用对象 - 对象是绑定方法对象的.im_self属性的值.

所以,我想知道是否matplotlibS" mpl_connect()是记住递增传递给它的参数的引用计数.如果不是(这是一个常见的错误),那么返回Foo().callback时没有什么可以保持匿名活着mpl_connect().

如果您可以轻松访问源代码,请查看mpl_connect()实现?你想看到C代码在做什么Py_INCREF();-)

编辑这看起来很相关,来自这里的文档:

画布仅保留对回调的弱引用.因此,如果回调是类实例的方法,则需要保留对该实例的引用.否则,实例将被垃圾收集并且回调将消失.

所以这是你的错 - LOL ;-)

  • `FigureCanvasBase` 的 `mpl_connect` 使用 `weakref.WeakKeyDictionary` 和 `weakref.ref`。[相关源码](https://github.com/matplotlib/matplotlib/blob/63f13c8d16c2b53ec2380b67f5b6ab45f6193bf9/lib/matplotlib/cbook.py#L474) (2认同)