19、面向对象-特殊方法
19、面向对象-特殊方法
1.析构方法
类析构函数(Destructor)是一种特殊的方法,它在对象或实例被销毁时自动调用,在 Python 中使用 __del__() 方法定义。类析构函数通常用于执行清理任务,例如释放资源、关闭文件等操作。
# 如何在 Python 中定义一个类析构函数class File:def __init__(self, path):self.path = pathself.file = open(path, mode='r')def read(self):return self.file.read()def __del__(self):self.file.close()print("File %s closed." % self.path)file = File('test.txt')
print(file.read())定义了一个 File 类,并在其中定义了 __init__()、read() 和 __del__() 方法。
其中,__init__() 方法接收 path 参数并打开该文件,read() 方法返回文件内容,而 __del__() 方法则在对象被销毁时自动调用,并在控制台输出一条信息和关闭文件句柄。
当我们创建 File 对象并读取文件内容时,并不需要手动关闭文件,因为类析构函数会在对象被销毁前自动调用,并执行清理任务。这样可以避免忘记关闭文件或其他资源造成的问题。类析构函数的触发条件是对象的引用计数降为 0。在 Python 中,引用计数指的是对象的所有符号表、栈和堆中对该对象的引用计数。当所有引用被删除或离开其作用域时,对象的引用计数降为 0,对象就会被销毁,同时类析构函数也会被自动调用。但需要注意的是,在 Python 中,类析构函数不像其他语言中的析构函数一样是必需的,因为垃圾回收机制可以自动管理内存并及时释放资源。
因此,类析构函数在 Python 中使用时应该谨慎,并仅在需要执行特定清理任务时才使用。del可以取消对象引用关系,例如: del file
2.垃圾回收机制
Python 中的垃圾回收机制是一种自动管理内存的机制,它可以检测和清理不再使用的内存,以避免内存泄漏和程序崩溃等问题。Python 中的垃圾回收机制基于引用计数(reference counting)和循环垃圾回收(Cycle-Detecting Garbage Collector)两种方式实现。引用计数是 Python 垃圾回收的主要方式,它通过跟踪对象的所有引用并在引用计数降为 0 时自动释放内存空间。当一个对象被赋值给一个变量、作为参数传递给函数、构成容器类型或者其他情况时,Python 会自动给该对象增加一个引用计数。如果一个对象的引用计数为 0,则表示当前没有任何指向该对象的引用了,此时该对象就可以被销毁并回收内存空间。循环垃圾回收机制是针对垃圾回收中存在的“循环引用”问题而设计的,这种问题通常发生在包含互相引用的对象或数据结构中。例如,两个对象之间互相引用,但又没有其他对象引用它们,这时引用计数已经失效,就需要使用循环垃圾回收机制进行清理。循环垃圾回收机制使用了一个标记清除算法和一个分代回收算法,可以及时检测并销毁无法通过引用计数自动回收的对象。Python 的垃圾回收机制是自动进行的,即程序员不需要手动调用垃圾回收函数或方法。Python 的解释器会自动监视和管理内存,并在内存空间紧张时触发垃圾回收机制。但如果出现了循环引用等复杂情况,也可以通过 `gc` 模块中的函数和变量来手动管理垃圾回收。例如,`gc.collect()` 函数可以手动触发垃圾回收,而 `gc.disable()` 和 `gc.enable()` 函数可以分别关闭和开启垃圾回收机制。总之,Python 的垃圾回收机制是一种非常强大且灵活的机制,它使得 Python 程序员不需要过多地关心内存管理问题,从而更加专注于业务逻辑实现。
循环垃圾回收(Cycle-Detecting Garbage Collector)是 Python 用于处理循环引用情况的一种垃圾回收机制。在 Python 中,当一个对象不再被任何变量、属性或其他对象所引用时,Python 解释器会自动删除该对象,以释放占用的内存空间。但是,如果有循环引用存在,则可能导致某些对象永远无法被回收,从而造成内存泄漏。循环垃圾回收机制可以解决这个问题。循环垃圾回收机制的基本实现原理是:定期扫描堆中所有的对象,并标记那些还在被引用的对象。对于那些没有被标记的对象,则被认为已经死亡,因此应该被回收。循环垃圾回收机制与引用计数相比,具有更高的开销和更慢的速度,因此只在必要时进行回收。循环垃圾回收过程包括两个主要步骤:标记和清除。1. 标记标记阶段的主要任务是找出所有仍然有用的对象并将它们标记为“活跃”的。算法从根对象开始遍历整个对象图,检查所有与根对象相关联的对象,并逐层遍历它们的属性或元素。在扫描过程中,所有找到的对象都被标记为“活跃”的。当标记完成时,那些仍然没有被标记的对象则可以安全地删除,以释放空间。2. 清除清除阶段的主要任务是回收那些没有被标记的对象。首先,算法遍历整个堆并将每个未被标记的对象添加到一个“待清理”列表中。之后,算法遍历这个列表并对其中的每个对象执行回收操作(例如,释放其内存、关闭它可能打开的文件等)。需要注意的是, Python 中循环垃圾回收机制虽然确实可以减少内存泄漏的问题,但也会带来一定的性能开销。因此,在编写代码时应该尽量避免和减少循环引用的情况,以免影响程序运行效率。
3.对象建立与单例模式
__new__() 是一个静态方法,用于创建类的新实例。在对象创建之前,Python 解释器会先调用 __new__() 方法,然后再调用 __init__() 方法进行初始化。
# 创建单例模式class Singleton(object):_instance = Nonedef __new__(cls, *args, **kwargs):if cls._instance is None:cls._instance = super().__new__(cls, *args, **kwargs)return cls._instanceobj1 = Singleton()
obj2 = Singleton()print(obj1 is obj2) # True定义了一个 Singleton 类,并重写了 __new__() 方法。
该方法判断类属性 _instance 是否已经被赋值,如果没有,则使用 super().__new__(cls) 创建一个新实例,并将其赋值给 _instance 属性。
如果已经存在实例,则直接返回实例。这样就保证了该类只有一个实例对象。
4.call
# __call__方法使得对象可以像函数一样被调用class MyClass:def __call__(self, x):return x * 2obj = MyClass()
result = obj(4) # 调用__call__方法
print(result) # 输出 8
5.str
# __str__用于返回对象的字符串表示形式,通常用于打印对象时使用。class Person:def __init__(self, name):self.name = namedef __str__(self):return f"This person's name is {self.name}"p = Person("John Doe")
print(p) # 输出 This person's name is John Doe
6.repr
# __repr__也用于返回对象的字符串表示形式,但它更多的是用于调试和开发中。class Point:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f"Point({self.x}, {self.y})"p = Point(3, 4)
print(p) # 输出 Point(3, 4)
print(repr(p)) # 输出 Point(3, 4)
如果一个对象没有实现__str__方法,则会使用默认的__repr__方法作为其字符串表示形式;如果一个对象没有实现__repr__方法,则会使用其父类的__repr__方法作为其字符串表示形式。
7.常见的特殊方法
以下是常见的特殊方法列表:
| 方法 | 说明 |
|---|---|
__init__(self[, ...]) | 构造函数,创建对象时调用 |
__new__(cls[, ...]) | 创建对象时调用,返回一个新的实例 |
__del__(self) | 对象被销毁时调用 |
__call__(self[, args...]) | 对象像函数一样被调用时调用 |
__len__(self) | 返回容器中元素个数 |
__getitem__(self, key) | 获取指定键的值 |
__setitem__(self, key, value) | 设置指定键的值 |
__delitem__(self, key) | 删除指定键的值 |
__contains__(self, item) | 判断指定元素是否在容器中 |
__str__(self) | 返回对象的字符串形式 |
__repr__(self) | 返回对象的表达式形式 |
__format__(self, format_spec) | 格式化输出 |
__enter__(self) | 进入上下文管理环境时调用 |
__exit__(self, exc_type, exc_val, exc_tb) | 离开上下文管理环境时调用 |
__add__(self, other) | 加法运算 |
__sub__(self, other) | 减法运算 |
__mul__(self, other) | 乘法运算 |
__truediv__(self, other) | 除法运算 |
__floordiv__(self, other) | 整除运算 |
__mod__(self, other) | 取模运算 |
__pow__(self, other[, modulo]) | 幂运算 |
__lt__(self, other) | 小于比较 |
__le__(self, other) | 小于等于比较 |
__eq__(self, other) | 等于比较 |
__ne__(self, other) | 不等于比较 |
__gt__(self, other) | 大于比较 |
__ge__(self, other) | 大于等于比较 |
这些特殊方法可以用于自定义类的行为,使得类的对象可以像系统内置对象一样具有某些特定的行为方式。需要注意的是,并不是所有的特殊方法都需要在自定义类中实现,只有在需要对类的行为进行特殊处理时才需要实现对应的特殊方法。
