【问题标题】:Python 3, super.__del__()Python 3,超级.__del__()
【发布时间】:2016-08-11 20:49:57
【问题描述】:

我在我定义的类中有一个__del__ 方法,用于删除通过在 ctypes 接口中调用 C++ new 创建的一些 C++ 对象。当我的类的实例被销毁时,我想删除这些对象。我有一个类的片段显示在这里:

class Graph(QtCore.QObject):
    def __init__(self):
        super().__init__()
        #list of objects created by calls to ctypes to create pointers to C++ objects which are instantiated with C++ new 
        self.graphs = []

    def __del__(self):
        print("in delete method")
        for graph in self.graphs:
            # call the C++ delete to free the storage used by this graph
            myctypes.graphDelete(graph)
        super().__del__()

当我的 Graph 类的一个实例被删除时,__del__ 方法被调用,我看到了我的打印语句,当我在 C++ 代码的析构函数方法中设置断点时,正如预期的那样,它删除了该对象。但是,当我的__del__ 方法调用super().__del__() 时,我收到错误消息:

super().__del__()
AttributeError: 'super' object has no attribute '__del__'

如果我在子类中定义了自己的__del__方法,如何确保父类(QtCore.QObject)被删除或者父类会被自动删除?

【问题讨论】:

  • 请尝试super(Graph, self).__del__()QtCore.QObject.__del__(self)。这应该没有什么区别,但也许它有效。
  • 谢谢 Kay,我刚刚尝试了这两种方法,但仍然出现属性错误。
  • @inwhack,我相信垃圾收集器会完成它的工作,清理未使用的实例/变量

标签: python python-3.x destructor super


【解决方案1】:

您派生的类没有__del__()。所以试图调用它是一个错误。

现在,如果您希望您的类用于多重继承方案,则方法解析顺序 (MRO) 中的下一个类实际上可能不是您的类的父类。而那个类,不管它是什么,都可能有一个__del__() 方法。因此,如果您担心这种情况,您可以使用 try 并吞下 AttributeError,或使用 hasattr(),或使用 getattr() 并将虚拟 lambda 作为默认值。

以下是每个示例:

# there is a minor bug here, can you guess what it is?
try:
    super().__del__(self)
except AttributeError:
    pass

# better versions of the above
s = super()
try:
    s.__del__
except AttributeError:
    pass
else:
    s.__del__(self)

# alternative 2
s = super()
if hasattr(s, "__del__"): 
    s.__del__(self)

# alternative 3
getattr(super(), "__del__", lambda self: None)(self)

【讨论】:

  • 我在代码注释中提到的“小错误”是我们没有捕获 only 由超类上的属性查找引起的 AttributeError。换句话说,如果 __del__ 存在于 MRO 中的下一个类上,但调用它会引发 AttributeError,则此错误将被错误地吞下而不是被报告。但在 60% 的情况下,它每次都有效。
【解决方案2】:

__del__的作用不是删除对象:它在对象被自动删除之前调用。因此,如果您的父类没有定义__del__,这很好。如果打扰您,请随时不要致电super().__del__()

作为记录,对象没有默认 __del__ 的原因是具有 __del__ 的对象在引用循环的情况下不会被垃圾收集(直到 Python 3.4)。如需更多信息,请阅读gc.garbage in Python 3.3gc.garbage in Python 3.4 的文档。

【讨论】:

  • 你能扩展第二段吗?我不明白。这是否意味着如果您的班级中有def __del__(self):,则该对象不会被垃圾收集?谢谢! (ps。主要是关于 Python 2.7)
  • 如果你有一个引用循环并且循环中的一个对象有__del__,那么这些对象永远不会被释放。见gc.garbage in 3.3gc.garbage in 3.4
【解决方案3】:

来自official documentation

在实例即将被销毁时调用。这也称为终结器或(不正确的)析构函数。如果基类有 del() 方法,则派生类的 del() 方法(如果有)必须显式调用它以确保正确删除实例。

如果我错了,请纠正我。如果基类不提供__del__,则不必调用它。捕捉AttributeError 并忽略它是一个好方法。

【讨论】:

  • 我认为这是正确的。似乎在 Python 中,默认情况下任何类都没有空的__del__。它只有在你定义它时才存在。
猜你喜欢
  • 2017-04-10
  • 2019-11-07
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
  • 2017-03-25
  • 2013-08-06
相关资源
最近更新 更多