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()

运行结果:

posted @ 2021-04-26 10:51  习久性成  阅读(1252)  评论(0编辑  收藏  举报