为什么在类的__init__中调用mpl_connect不起作用?

3
我正在制作一个交互式的pyplot图表,并使用“fig.canvas.mpl_connect(event,function)”来响应按键或鼠标操作。它可以正常工作。但是,为了方便导入,我需要将函数压缩成一个类。mpl_connect函数将在类的__init__函数中调用。但是这会导致它无法工作。只有当mpl_connect在类外部与类内部的函数相关联时,它才能正常工作。
当然,我已经尝试过不使用类进行调用,这也可以正常工作。并且为了证明问题出现在类的__init__函数中,我在类外部以类内部函数的引用调用了mpl_connect。
下面是一个简化版的示例代码,它是一个简单的事件处理程序,当您用鼠标单击pyplot图表时,它会在控制台上打印“yes”:
-> 没有使用类可以正常工作!但在其他程序中导入时不可靠。
import matplotlib.pyplot as plt
def abc(event):
   print("yes")
fig, ax = plt.subplots()
fig.canvas.mpl_connect("button_press_event",abc)
plt.show()

->无法工作,不会打印“yes”(即使使用self.fig)。

import matplotlib.pyplot as plt
class test():
    def __init__(self):
        fig, ax = plt.subplots()
        fig.canvas.mpl_connect("button_press_event",self.abc)
    def abc(self, event):
        print("Yes")
test()
plt.show()

->能够工作,现在有一个存储函数的类,但应该使用对该类的引用,并且它看起来不太好:

import matplotlib.pyplot as plt
class test():
    def __init__(self):
        self.FIG, ax = plt.subplots()
    def abc(self, event):
        print("Yes")  
A = test()
A.FIG.canvas.mpl_connect("button_press_event",A.abc)
plt.show()

当我在类的初始化期间调用mpl_connect函数时,我希望它在我点击图表时打印出“是”,这是正常、逻辑的Python方式。我认为这是一个bug。谢谢。

编辑,通过添加弱引用已修复。

import matplotlib.pyplot as plt
class test():
    def __init__(self):
        self.fig, ax = plt.subplots()
        self.cid_abc = self.fig.canvas.mpl_connect("button_press_event",self.abc)
    def abc(self, event):
        print("Yes")
mytest = test()
plt.show()
1个回答

2
您需要保留由`mpl_connect`创建的回调ID的引用。正如`CallbackRegistry`文档字符串所述:
“实际上,应该始终在不再需要时断开所有回调,以避免悬空引用(因此会内存泄漏)。但是,Matplotlib中的真实代码很少这样做,并且由于其设计,很难放置这种代码。为了解决这个问题并防止这类内存泄漏,我们只存储已绑定方法的弱引用,因此当目标对象需要销毁时,CallbackRegistry将不会保持它的存活。”
换句话说,您需要将`mpl_connect`的返回值分配给一个实例变量,例如:
self.cid = fig.canvas.mpl_connect("button_press_event", self.abc)

类似于您在事件处理指南中找到的方式。

2
感谢您的评论。我将这行代码替换为:"self.cid_abc = fig.canvas.mpl_connect("button_press_event", self.abc)"。然而,不幸的是,这并没有解决这个问题。 - johnabro
1
哦,你丢失了对整个test()实例的引用。抱歉,我没有注意到。可以使用mytest = test()或类似的方式来解决。 - ImportanceOfBeingErnest
1
太好了!非常感谢您!从现在开始,我会确保使用弱引用。 - johnabro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接