首页 > 解决方案 > 为什么在类的 __init__ 中调用 mpl_connect 不起作用?

问题描述

当按下键或鼠标时,我正在使用“fig.canvas.mpl_connect(event,function)”制作交互式 pyplot 图。它按预期工作。但是,为了使其易于导入,我需要将函数压缩到一个类中。mpl_connect 函数将在类的 __init__ 函数中调用。但这使它无法工作。只有当 mpl_connect 在类外调用类内函数时,它才起作用。

当然,我尝试在没有课程的情况下调用它,并且按预期工作。为了说明问题发生在类的 __init__ 函数内部,我在类外部调用了 mpl_connect 以引用类内部的函数。

这是我试图实现的浓缩的鸭测试版本。这是一个简单的事件处理程序,当您用鼠标单击 pyplot 图形时,它会使控制台打印“是”。:

-> WORKS,虽然没有课!导入到其他程序时不可靠。

import matplotlib.pyplot as plt
def abc(event):
   print("yes")
fig, ax = plt.subplots()
fig.canvas.mpl_connect("button_press_event",abc)
plt.show()

-> 不工作,不打印“是”(即使使用了 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()

-> DOES WORK,现在有一个存储函数的类,但是应该使用对类的引用,它看起来不太好:

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 方式。我相信这是一个错误。谢谢你。

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

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()

标签: pythonclassmatplotlibevents

解决方案


您将需要保留对由创建的回调 id 的引用mpl_connect。作为CallbackRegistry文档字符串制定:

在实践中,当不再需要所有回调时,应始终断开所有回调,以避免悬空引用(从而导致内存泄漏)。然而,Matplotlib 中的实际代码很少这样做,并且由于其设计,放置这种代码相当困难。为了解决这个问题并防止此类内存泄漏,我们只存储对绑定方法的弱引用,因此当目标对象需要终止时,CallbackRegistry不会使其保持活动状态。

换句话说,您需要将返回分配给mpl_connect实例变量,例如

self.cid = fig.canvas.mpl_connect("button_press_event", self.abc)

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


推荐阅读