【Python语言基础】19、垃圾回收

文章目录

    • [1. 垃圾回收](#1. 垃圾回收)
      • [1.1 引用计数-日常检查货物标签](#1.1 引用计数-日常检查货物标签)
      • [1.2 标记-清除算法:处理互相依赖的货物](#1.2 标记-清除算法:处理互相依赖的货物)
      • [1.3 分代回收:根据货物新旧安排清理频率](#1.3 分代回收:根据货物新旧安排清理频率)
    • [2. 特殊方法](#2. 特殊方法)
      • [2.1 构造和析构方法](#2.1 构造和析构方法)
      • [2.2 字符串表示方法](#2.2 字符串表示方法)
      • [2.3 比较方法](#2.3 比较方法)
      • [2.4 容器相关方法](#2.4 容器相关方法)
      • [2.5 可调用对象方法](#2.5 可调用对象方法)

1. 垃圾回收

计算机的内存想象成一个大仓库,里面存放着各种各样的货物(对象),而 Python 的垃圾回收机制就如同仓库里的清洁工,会定期检查房间(内存),把那些你不再使用的物品(对象)清理掉,释放出空间,让你可以继续使用内存。

而在程序中没有被引用的对象就是垃圾,垃圾对象过多会影响到程序的运行速度。

下面咱们就结合生活场景详细说说。

1.1 引用计数-日常检查货物标签

在这个大仓库中,每一件货物上都挂着标签,每个标签代表着一个对该货物的引用。

比如,有一个叫 "苹果" 的货物,当仓库管理员小王在他的货物清单上记录了 "苹果" 时,"苹果" 这个货物就有了一个标签,代表小王引用了它。

python 复制代码
# 仓库里新来了一批苹果
apples = ["红富士", "蛇果"]  
# 小李也在他的清单上记录了苹果
other_apples = apples  

此时,"苹果" 货物上就有了两个标签,意味着它的引用计数是 2。

当小王不再需要 "苹果" 了,他会从自己的清单上划掉 "苹果",这就相当于删除了一个引用。

python 复制代码
# 小王不再关注苹果了
del apples  

这时,"苹果" 货物上就只剩下一个标签,引用计数变为 1。

如果小李也不再需要 "苹果",从他的清单上划掉 "苹果",引用计数就变为 0。

python 复制代码
# 小李也不再关注苹果了
del other_apples  

一旦引用计数为 0,清洁工(垃圾回收机制)就会立刻发现,然后把 "苹果" 货物从仓库中清理出去,释放出存放 "苹果" 的空间。

1.2 标记-清除算法:处理互相依赖的货物

有时候,仓库里会出现一些特殊情况,有两件货物相互捆绑在一起,而且没有其他地方提到它们。

比如,"箱子" 货物里面装着 "钥匙" 货物,同时 "钥匙" 又能打开 "箱子",它们相互依赖。

python 复制代码
class Box:
    pass

class Key:
    pass

# 仓库里有了一个箱子和一把钥匙
box = Box()
key = Key()
# 箱子里装着钥匙
box.key = key
# 钥匙能打开箱子
key.box = box
# 仓库管理员不再需要它们了
del box
del key

在这种情况下,"箱子" 和 "钥匙" 虽然看起来没人要了,但因为它们相互引用,各自的引用计数都不为 0。

这时,日常检查标签的方法(引用计数)就失效了。

于是,清洁工就会启动标记 - 清除算法。他先把仓库里所有的货物都标记为 "可能要清理",然后从仓库的入口(根对象,如全局变量)开始,沿着货物之间的关联关系进行检查。

如果发现某个货物可以从入口到达,就把它标记为 "保留"。经过一轮检查后,那些仍然标记为 "可能要清理" 的货物,就是真正的垃圾,清洁工就会把它们清理掉。

1.3 分代回收:根据货物新旧安排清理频率

仓库里的货物有新有旧,有些货物刚进来没多久就可能会被处理掉,而有些货物则会长期存放在仓库里。

清洁工根据这个特点,把货物分成了三代。

新进入仓库的货物属于第 0 代,清洁工对第 0 代货物的检查频率最高,因为它们很可能很快就会变成垃圾。

经过一次检查后还没被清理掉的货物,就会被移到第 1 代。第 1 代货物的检查频率会相对低一些。

而那些经过多次检查都还没被清理的货物,会被移到第 2 代,第 2 代货物的检查频率最低。

python 复制代码
# 这是新进来的第 0 代货物
new_item = [1, 2, 3]
# 经过一段时间,new_item 如果没被清理,可能会进入第 1 代
# 再经过一段时间,如果还没被清理,可能会进入第 2 代

通过这种分代回收的方式,清洁工可以更高效地管理仓库空间,优先处理那些更可能成为垃圾的货物。

总结

Python 的垃圾回收机制就像这位聪明的清洁工,通过引用计数、标记 - 清除算法和分代回收算法,有条不紊地管理着计算机的内存仓库。

2. 特殊方法

在 Python 里,特殊方法(也叫魔术方法)是一类具有特殊名称的方法,它们的名字以双下划线 __ 开头和结尾。这些方法能让你自定义类的行为,使类的使用更符合 Python 的习惯。

特殊方法一般不需要我们手动调用,需要在一些特殊情况下自动执行

2.1 构造和析构方法

  • init:这是最常用的特殊方法之一,用于在创建对象时进行初始化操作。
python 复制代码
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("张三", 25)
  • del:当对象被销毁时会调用这个方法,可用于执行一些清理操作,比如关闭文件、释放资源等。
python 复制代码
class Resource:
    def __init__(self):
        print("资源已创建")

    def __del__(self):
        print("资源已释放")

r = Resource()
del r

2.2 字符串表示方法

  • str:用于返回对象的字符串表示形式,通常供用户阅读。当使用 print 函数打印对象或使用 str() 函数转换对象时会调用该方法。
python 复制代码
class Book:
    def __init__(self, title):
        self.title = title

    def __str__(self):
        return f"这本书的名字是 {self.title}"

book = Book("Python入门")
print(book)
  • repr:返回对象的 "官方" 字符串表示形式,通常用于调试和开发。当在交互式环境中直接输入对象名或使用 repr() 函数时会调用该方法。
python 复制代码
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Point({self.x}, {self.y})"

point = Point(1, 2)
print(repr(point))

2.3 比较方法

  • eq:用于定义对象的相等比较规则,当使用 == 运算符比较两个对象时会调用该方法。
python 复制代码
class Student:
    def __init__(self, id):
        self.id = id

    def __eq__(self, other):
        return self.id == other.id

s1 = Student(1)
s2 = Student(1)
print(s1 == s2)

类似的还有 ne (不等于)、lt (小于)、le (小于等于)、gt (大于)、ge(大于等于)等方法。

2.4 容器相关方法

  • len:用于返回对象的长度,当使用 len() 函数时会调用该方法。
python 复制代码
class MyList:
    def __init__(self, items):
        self.items = items

    def __len__(self):
        return len(self.items)

my_list = MyList([1, 2, 3])
print(len(my_list))
  • getitem:用于实现通过索引访问对象中的元素,当使用 obj[index] 这种方式访问对象时会调用该方法。
python 复制代码
class MyList:
    def __init__(self, items):
        self.items = items

    def __getitem__(self, index):
        return self.items[index]

my_list = MyList([1, 2, 3])
print(my_list[1])

还有 setitem (用于设置元素)、delitem(用于删除元素)等方法。

2.5 可调用对象方法

  • call:让对象可以像函数一样被调用。
python 复制代码
class Adder:
    def __call__(self, a, b):
        return a + b

adder = Adder()
result = adder(3, 5)
print(result)
相关推荐
noravinsc29 分钟前
python提升图片清晰度
开发语言·python
声声codeGrandMaster33 分钟前
Django之modelform使用
后端·python·django
一一Null35 分钟前
Android studio 动态布局
android·java·android studio
假女吖☌37 分钟前
Maven 编译指定模版
java·开发语言·maven
体育分享_大眼3 小时前
从零搭建高并发体育直播网站:架构设计、核心技术与性能优化实战
java·性能优化·系统架构
水w3 小时前
【Python爬虫】简单案例介绍1
开发语言·爬虫·python
琢磨先生David4 小时前
Java 在人工智能领域的突围:从企业级架构到边缘计算的技术革新
java·人工智能·架构
计算机学姐4 小时前
基于SpringBoo的地方美食分享网站
java·vue.js·mysql·tomcat·mybatis·springboot·美食
FreakStudio6 小时前
一文速通 Python 并行计算:07 Python 多线程编程-线程池的使用和多线程的性能评估
python·单片机·嵌入式·多线程·面向对象·并行计算·电子diy
Hanson Huang7 小时前
【数据结构】堆排序详细图解
java·数据结构·排序算法·堆排序