python之__del__()魔方方法:销毁对象,内存回收
前言
①python通过调用 __init__() 方法构造当前类的实例化对象。【创建对象时,python解释器默认调用 __init__() 方法】
② __del__() 方法的功能正好与 __init__() 方法相反,其用来销毁实例化对象。【删除一个对象时,python解释器默认调用 __del__() 方法】
③事实上在编写程序时,如果之前创建的类实例化对象后续不再使用,最好在适当位置手动将其销毁,释放其占用的内存空间(整个过程称为垃圾回收(简称GC))。
④大多数情况下,Python 开发者不需要手动进行垃圾回收,因为 Python 有自动的垃圾回收机制,能自动将不需要使用的实例对象进行销毁。
实例讲解
__del__() :
使用场景:
1、当删除对象时,Python解析器会默认调用 __del__() 方法,即对象引用执行完后python会自动调用 __del__() 方法。
2、销毁(释放)内存中的对象时回调 __del__() 方法。
实例一:
class CLanguage: def __init__(self): print("调用 __init__() 方法构造对象") def __del__(self): print("调用__del__() 销毁对象,释放其空间") clangs = CLanguage() del clangs
运行结果:
【注意1】:不能误认为,只要该实例对象调用 __del__() ,该实例对象所占用的内存空间就会被释放。
比如:
class CLanguage: def __init__(self): print("调用 __init__() 方法构造对象") def __del__(self): print("调用__del__() 销毁对象,释放其空间") clangs = CLanguage() # 添加一个引用clangs对象的实例对象 cl = clangs del clangs # 删除实例对象(实际上是对实例对象的引用计数减1) print("***********")
运行结果:上述代码最后一行输出信息,是程序执行即将结束时调用 __del__() 方法输出的。
解释说明:
①当程序中有其它变量(比如上述代码中的cl变量)引用该实例对象时,即便手动调用 __del__() 方法,该方法也不会立即执行。这和 Python 的垃圾回收机制的实现有关。
②Python 采用自动引用计数(简称 ARC)的方式实现垃圾回收机制。该方法的核心思想是:每个 Python 对象都会配置一个计数器,初始 Python 实例对象的计数器值都为 0,如果有变量引用该实例对象,其计数器的值会加 1,依次类推;反之,每当一个变量取消对该实例对象的引用,计数器会减 1。如果一个 Python 对象的的计数器值为 0,则表明没有变量引用该 Python 对象,即证明程序不再需要它,此时 Python 就会自动调用 __del__() 方法将其回收。
③以上面程序中的 clangs 为例,实际上构建 clangs 实例对象的过程分为 2 步,先使用 CLanguage() 调用该类中的 __init__() 方法构造出一个该类的对象(将其称为 C,计数器为 0),并立即用 clangs 这个变量作为所建实例对象的引用( C 的计数器值 + 1)。在此基础上,又有一个 cl变量引用 clangs(其实相当于引用 CLanguage(),此时 C 的计数器再 +1 ),这时如果调用 del clangs 语句,只会导致 C 的计数器减 1(值变为 1),因为 C 的计数器值不为 0,因此 C 不会被销毁(不会执行 __del__() 方法)。
④再次举例:当执行 del cl 语句时,其应用的对象实例对象 C 的计数器继续 -1(变为 0),对于计数器为 0 的实例对象,Python 会自动将其视为垃圾进行回收。
class CLanguage: def __init__(self): print("调用 __init__() 方法构造对象") def __del__(self): print("调用__del__() 销毁对象,释放其空间") clangs = CLanguage() # 添加一个引用clangs对象的实例对象 cl = clangs del clangs # 删除实例对象(实际上是对实例对象的引用计数减1) print("***********") del cl # 删除实例对象(实际上是对实例对象的引用计数再减1) print("-----------")
运行结果:
实例二:
class User: def __init__(self, username): self.user = username print('User 初始化成功---') def get_info(self): print(self.user) def __del__(self): print('User 对象被回收---') if __name__ == '__main__': # 创建一个user对象 u = User(username='XXX') # 删除该User对象 del u print('del u -------------')
运行结果:
代码详解:
u = User() 在内存中创建了一个 User 对象,并且让变量 u 引用内存中的 User 对象。
del u 删除变量 u , 此时内存中的 User 对象没有任何变量对其引用,Python解析器就会回调 __del__() 方法,回收内存。
实例三:
class User: def __init__(self, username): self.user = username print('User 初始化成功---') def get_info(self): print(self.user) def __del__(self): print('User 对象被回收---') if __name__ == '__main__': u1 = User('XXX') u2 = u1 del u1 print('del u1 -------') del u2 print('del u2 -------')
运行结果:
代码解析:
u1 = User() 创建一块存放 User 对象的内存,并且,变量 u1 指向该内存。
u2 = u1 此处又新建变量 u2, 并且 u2 引用了 u1 的内存地址,此时,u1 和 u2 同时引用同一个内存地址。
del u1 删除 u1 时,删除该变量对User对象的引用,此时,由于内存中的 User 对象还在被 u2 引用,所以不会回收该内存(不会回调 __del__() 方法)。
del u2 删除 u2 后,内存中的 User 对象已经没有引用的变量,此时解释器才会对内存进行回收,回调 __del__() 方法。
实例四:当实例对象的引用计数为0时,python解释器会自动调用 __del__() 销毁对象,回收内存空间。
class User: def __init__(self, username): self.user = username print('User 初始化成功---') def get_info(self): print(self.user) def __del__(self): print('User 对象被回收---') if __name__ == '__main__': User('XXX').get_info()
运行结果: