Python 析构器——销毁对象

原文:https://www.studytonight.com/python/destructors-in-python

就像构造器用于创建和初始化一个对象一样,析构器用于销毁该对象并执行最终清理。

虽然在 python 中,我们确实有垃圾收集器来清理内存,但是当一个对象被取消引用或销毁时,需要释放的不仅仅是内存,还有很多其他资源,比如关闭打开的文件、关闭数据库连接、清理缓冲区或缓存等。因此,当我们说最终清理时,它不仅仅意味着清理内存资源。

在我们的上一个教程中,我们学习了如何使用__new__方法创建对象,以及如何使用__init__方法初始化对象。在本教程中,我们将学习如何销毁对象。

正如我们在上一个教程中明确指出的那样,__init__方法不一定是构造器方法,因为它只能初始化对象变量,而不能创建对象,这是通过__new__方法完成的。

同样,析构器的概念在 python 中也有点模糊,虽然通常__del__方法被认为是析构器方法,所以让我们看看如何使用这个方法来销毁一个类的对象。


使用__del__方法

下面我们有一个类Example的简单代码,其中我们使用了__init__方法来初始化我们的对象,而我们定义了__del__方法来充当析构器。

class Example:
    def __init__(self):
        print ("Object created");

    # destructor
    def __del__(self):
        print ("Object destroyed");

# creating an object
myObj = Example();
# to delete the object explicitly
del myObj;

对象已创建对象已销毁


需要注意的几点

  1. 就像析构器是构造器的反函数一样,函数__del__也是函数__new__的反函数。因为__new__是创造对象的函数。
  2. 当任何对象的引用计数变为零时,对该对象调用__del__方法。
  3. 由于进行引用计数,因此对于一个对象来说,如果超出范围就不需要调用__del__方法。只有当引用计数为零时,才会调用析构器方法。

角落案例:当析构器表现不好时

正如我们在开头已经提到的,使用__del__并不是对不再需要的对象执行最终清理的完全证明解决方案。

这里我们讨论了两种这样的情况,其中__del__函数的行为是荒谬的。


1.循环引用

循环引用是指两个对象相互引用的情况。在这种情况下,当这两个对象都失去引用时,python 会困惑于首先销毁哪个对象,为了避免任何错误,它不会销毁它们中的任何一个。

这里有一个演示循环引用的例子,

class Foo():
    def __init__(self, id, bar):
        self.id = id;
        # saving reference of Bar object
        self.friend = bar;
        print ('Foo', self.id, 'born');

    def __del__(self):
        (print 'Foo', self.id, 'died');

class Bar():
    def __init__(self, id):
        self.id = id;
        # saving Foo class object in variable
        # 'friend' of Bar class, and sending
        # reference of Bar object for Foo object
        # initialisation
        self.friend = Foo(id, self);
        print ('Bar', self.id, 'born')

    def __del__(self):
        print ('Bar', self.id, 'died')

b = Bar(12)

福 12 出生酒吧 12 出生


2.__init__方法异常

面向对象编程中,析构器仅在对象成功创建的情况下被调用,因为如果构造器中出现任何异常,那么构造器本身就会销毁该对象。

但是在 python 中,如果在初始化对象时__init__方法出现任何异常,在这种情况下也会调用方法__del__

因此,即使对象从未被正确初始化,__del__方法将尝试清空所有的资源和变量,并可能导致另一个异常。

class Example():
    def __init__(self, x):
        # for x = 0, raise exception
        if x == 0:
            raise Exception();
        self.x = x;

    def __del__(self):
        print (self.x)

# creating an object
myObj = Example();
# to delete the object explicitly
del myObj

例外例外。属性错误:“‘示例’对象在中没有属性‘x’”>被忽略