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;
对象已创建对象已销毁
需要注意的几点
- 就像析构器是构造器的反函数一样,函数
__del__也是函数__new__的反函数。因为__new__是创造对象的函数。 - 当任何对象的引用计数变为零时,对该对象调用
__del__方法。 - 由于进行引用计数,因此对于一个对象来说,如果超出范围就不需要调用
__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
例外例外。属性错误:“‘示例’对象在