第8.18节 Python类中内置析构方法__del__
一、 引言
基本上所有支持OOP设计的语言都支持析构方法(也称析构函数),析构方法都是在对象生命周期结束时调用,一般用来实施实例相关生命周期内访问数据的扫尾工作,包括关闭文件、释放内存、输出日志、清理数据等。
二、 析构方法语法
Python中所有类的析构方法都是特殊方法__del__,析构方法同样是一个实例方法,其语法如下:
del(self)
self就是对象自身,所有实例方法都有该参数,真正调用时无需传递。
析构方法没有返回值要求。
析构方法语法很简单,没有需要过多解释的地方。
三、 析构方法的使用
- 析构方法比较特殊,这是因为它是Python中定义的特殊方法,在对象销毁时自动执行,但在object类内却没有该方法,在自定义类定义时,并没有要求一定要自己定义析构方法,因此在自定义类及其自定义父类中没有定义__del__析构方法时,该类就没有析构方法;
- 如果子类定义了析构方法,其派生的父类也定义了析构方法,则在子类的析构方法中必须调用父类的析构方法;
- 当程序不再需要一个 Python 对象时,系统必须把该对象所占用的内存空间释放出来,这个过程被称为垃圾回收(GC,Garbage Collector),Python 会自动回收所有对象所占用的内存空间,开发者无须关心对象垃圾回收的过程。垃圾回收会自动触发对析构方法的调用;
- 使用del删除实例对象时,并不一定会触发析构方法的调用
1>Python中可能存在多个实例ID相同的情况,如实例a通过赋值语句赋值给b时,此时a与b的ID相同,就认为该ID对象上增加了一个引用;如果一个对象有多个变量引用它,那么 del 其中一个变量是不会回收该对象的。这个销毁的动作还是需要等待对象引用没有了以后才能够完成。
2>Python 采用自动引用计数(ARC:Automatic Reference Counting)方式来判断对象是否需要被回收,当程序中有一个变量引用该对象时,Python 会自动设置该对象引用计数为1;当程序中每增加一个变量引用该 Python 对象(如赋值)时,Python 会自动对该对象引用计数加1,反之如果每减少一个(如del 变量)变量的引用,该对象引用计数就减一,当对象的引用计数变成 0,则说明不再有变量引用该对象,Python 就会回收该对象,此时才会调用析构方法;
3>大部分时候,Python 的 ARC 都能准确、高效地回收系统中的每个对象。但如果系统中出现循环引用的情况,如两个对象下的属性相互指向对方(如双向链表),但两个对象都没有单独的变量引用它们,此时两个对象的引用计数并不是0,而都是1,但实际上程序已经不再有变量引用它们,此时 Python 的垃圾回收器就可能没那么快,要等专门的循环垃圾回收器(Cyclic Garbage Collector)来检测并回收这种引用循环。 - 由于调用 del() 方法时周边状况已不确定,如部分关联对象已经回收、部分模块删除了等,因此Python对在__del__() 方法执行期间发生的异常将被忽略,改为打印一个警告到 sys.stderr;
- 老猿验证在交互模式执行del实例变量时,哪怕对象没有引用了,Python也不一定马上执行垃圾回收和__del__方法,会出现比较复杂的情况,可能在del语句执行一段时间后执行其他语句时突然释放。对此老猿不展开多说,为此老猿下面的代码是通过文件方式执行的。
四、 例子 - 案例说明
本节定义Vehicle类和Car类,后者是从前者派生的。将在定义实例后,将实例赋值给另一个变量,然后使用del删除变量,看看是否能触发析构方法。 - 源代码
class Vehicle():
def __init__(self,wheelcount,power):
self.wheelcount = wheelcount
self.power = power
print("In Vehicle init,objectid = {:#016X}".format(id(self)))
def __del__(self):
print("in Vehicle __del__,delete objectid = {:#016X}".format(id(self)))
print("Vehicle deleted")
class Car(Vehicle):
def __init__(self, power,oilcostper100km):
print("In Car init,objectid = {:#016X}".format(id(self)))
self.oilcostper100km = oilcostper100km
super().__init__(4, power)
def __del__(self):
print("in Car __del__,delete objectid = {:#016X}".format(id(self)))
super().__del__()
print("Car deleted")
print("execut Car('汽油发动机',10)...")
car = Car('汽油发动机',10) #对象引用数为1
c=car #对象引用数为2
print("execut del car...")
del car #对象引用数为1
print("execut del c...")
del c #对象引用数为0,应该触发析构方法
print("Prog end.")
源代码截图:

执行结果截图:

案例总结
通过上述截图可以看出,在引用数为0才触发了析构方法。
最后,老猿需要强调一点,在Python中析构方法的使用要慎重,一是因为del变量不一定触发析构方法,二是因为调用 del() 方法时周边状况已不确定,三是Python有自己的垃圾回收机制执行相关资源的回收和清理,因此编程者意图在析构方法中实施的操作不一定会按照编程者的意图完整实施。
本节对Python析构方法的语法、使用以及注意事项进行了深入介绍,并举例进行了验证,请大家理解,并慎重使用!
老猿Python,跟老猿学Python!
博客地址:https://blog.csdn.net/LaoYuanPython
请大家多多支持,点赞、评论和加关注!谢谢!
第8.18节 Python类中内置析构方法__del__的更多相关文章
- 第8.9节 Python类中内置的查看直接父类的__bases__属性
终于介绍完了__init__方法和__new__方法,接下来轻松一下,本节介绍类中内置的__bases__属性. 一. 语法释义 Python 为所有类都提供了一个 bases 属性,通过该属性可以查 ...
- 第8.14节 Python类中内置方法__str__详解
一. object类内置方法__str__和函数str 类的内置方法__str__和内置函数str实际上实现的是同一功能,实际上str调用的就是__str__方法,只是调用方式不同,二者的调用语法如下 ...
- 第8.13节 Python类中内置方法__repr__详解
当我们在交互环境下输入对象时会直接显示对象的信息,交互环境下输入print(对象)或代码中print(对象)也会输出对象的信息,这些输出信息与两个内置方法:__str__方法和__repr__方法有关 ...
- python - 类的内置 attr 方法
类的内置 attr 方法 #类的内置 attr 方法: # __getattr__ # __setattr__ # __delattr__ # __getattr__ #到调用一个类不存在数参数时,将 ...
- python -- 类中--内置方法
isinstance 和 issubclass isinstance(obj,b) 检查是否obj是否是类b的对象 class A(object):pass class B(A):pass b=B ...
- 第7.17节 Python类中的静态方法装饰器staticmethod 定义的静态方法深入剖析
第7.17节 Python类中的静态方法装饰器staticmethod 定义的静态方法深入剖析 静态方法也是通过类定义的一种方法,一般将不需要访问类属性但是类需要具有的一些能力可以静态方法提供. 一 ...
- 第7.14节 Python类中的实例方法详析
第7.14节 Python类中的实例方法详析 一. 实例方法的定义 在本章前面章节已经介绍了类的实例方法,实例方法的定义有三种方式: 1. 类体中定义实例方法 第一种方式很简单,就是在类体 ...
- 第8.6节 Python类中的__new__方法深入剖析:调用父类__new__方法参数的困惑
上节<第8.5节 Python类中的__new__方法和构造方法__init__关系深入剖析:执行顺序及参数关系案例详解>通过案例详细分析了两个方法的执行顺序,不知大家是否注意到了,在上述 ...
- 第8.12节 Python类中使用__dict__定义实例变量和方法
上节介绍了使用实例的__dict__查看实例的自定义属性,其实还可以直接使用__dict__定义实例变量和实例方法. 一. 使用__dict__定义实例变量 语法: 对象名. dict[属性名] = ...
随机推荐
- linux磁盘已满,查看那个目录文件最占磁盘空间并解决没有内存不耗费资源删除
df -Th查看磁盘空间占用情况 [root@IntelRC-Nginx-N023 ~]# df -Th Filesystem Type Size Used Avail Use% Mounted on ...
- wpf 全局异常捕捉+错误日志记录+自动创建桌面图标
/// /// 创建桌面图标 /// public static void CreateShortcutOnDesktop(string LnkName) { String shortcutPath ...
- Uipath_考证学习之路
写在前面 第一次考证的时候,就是为了考证而考证,从网上获取了试题,修改了一下,就通过了,对 REFramework的了解甚少,经过几周的学习,决定赶在 4.30号考证收费之前再重新考一次. 原文章发表 ...
- Mongodb和Hbase的对比
Mongodb和Hbase的对比 1.Mongodb bson文档型数据库,整个数据都存在磁盘中,hbase是列式数据库,集群部署时每个familycolumn保存在单独的hdfs文件中. 2.Mon ...
- 菜鸟试做GUI简单数据库查询界面 python+tkinter+mysql
一.准备工作: 1.安装mysql3.7,创建一个test数据库,创建student表,创建列:(列名看代码),创建几条数据 (以上工作直接用navicat for mysql工具完成) 二.代码: ...
- 定位一个网络问题引起的ceph异常
前言 有一个ceph环境出现了异常,状态就是恢复异常的慢,但是所有数据又都在走,只是非常的慢,本篇将记录探测出问题的过程,以便以后处理类似的问题有个思路 处理过程 问题的现象是恢复的很慢,但是除此以外 ...
- 源码分析:CountDownLatch 之倒计时门栓
简介 CountDownLatch 是JDK1.5 开始提供的一种同步辅助工具,它允许一个或多个线程一直等待,直到其他线程执行的操作完成为止.在初始化的时候给定 CountDownLatch 一个计数 ...
- powershell过杀软工具-xencrypt
在红队攻击中,绕杀软是一个比较常见的技术.对于绕过杀软的方法,有基于黑白名单的,有基于shellloader的,也有基于加密与混淆的.最近在发现了这样一款过杀软的工具,推荐给有缘人,嘻嘻 ...
- Java 中常见的细粒度锁实现
上篇文章大致说了下 ReentrantLock 类的使用,对 ReentrantLock 类有了初步的认识之后让我们一起来看下基于 ReentrantLock 的几种细粒度锁实现. 这里我们还是接着用 ...
- C++中class和struct区别
1.存储不同 结构体使用栈存储(Stack Allocation),而类使用堆存储(Heap Allocation). 栈的空间相对较小.但是存储在栈中的数据访问效率相对较高. 堆的空间相对较大.但是 ...