Python 中的魔法方法(Magic Methods),也被称为“双下划线方法”(Dunder Methods),是赋予自定义类“魔法”般行为的核心机制。它们通过实现 Python 预定义的特殊方法,让你可以自定义对象在各种内置操作下的行为,例如创建、打印、运算、索引、迭代等。魔法方法的名字都以双下划线 __ 开头和结尾。它们通常不由你直接调用,而是由 Python 解释器在特定时机自动触发。
🧙♂️ 对象生命周期方法
这类方法控制着对象的创建、初始化和销毁过程。
__new__(cls, ...): 在 __init__ 之前被调用,负责创建并返回一个新的实例。它主要用于控制实例的创建过程,例如实现单例模式或继承不可变类型(如 str, int)。__init__(self, ...): 在 __new__创建实例后被调用,负责初始化
实例,即设置对象的初始属性。这是最常用的魔术方法。__del__(self): 当一个对象即将被垃圾回收时调用,用于执行清理工作,如关闭文件或网络连接。
class Resource: def __new__(cls, name): print("1. 创建实例") return super().__new__(cls) def __init__(self, name): print("2. 初始化实例") self.name = name def __del__(self): print(f"3. 销毁实例: {self.name}")# 输出:# 1. 创建实例# 2. 初始化实例# (当 res 被回收时) 3. 销毁实例: my_fileres = Resource("my_file")del res
📝 对象表示方法
这类方法定义了对象如何被转换为字符串,用于打印和调试。
__str__(self): 定义使用 print(obj) 或 str(obj) 时对象的“用户友好”字符串表示。__repr__(self): 定义在交互式命令行直接输入 obj 或使用 repr(obj)时的字符串表示。它通常用于调试,应尽量返回一个能重现该对象的、明确的字符串。
class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f"{self.name}, {self.age}岁" # 易读 def __repr__(self): return f"Person('{self.name}', {self.age})" # 明确,可用于调试p = Person("Alice", 25)print(p) # 调用 __str__: Alice, 25岁print(repr(p)) # 调用 __repr__: Person('Alice', 25)
➕ 运算符重载方法
通过实现这些方法,你的自定义对象就能像内置类型一样使用 +, -, == 等运算符。
算术运算符
__add__(self, other): 对应 + 运算。__sub__(self, other): 对应 - 运算。__mul__(self, other): 对应 * 运算。
比较运算符
__eq__(self, other): 对应 == 运算。__lt__(self, other): 对应 < 运算。__gt__(self, other): 对应 > 运算。
class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __eq__(self, other): return self.x == other.x and self.y == other.y def __str__(self): return f"Vector({self.x}, {self.y})"v1 = Vector(1, 2)v2 = Vector(3, 4)print(v1 + v2) # 调用 __add__: Vector(4, 6)print(v1 == v2) # 调用 __eq__: False
📦 模拟容器方法
实现这些方法可以让你的对象表现得像列表或字典等容器。
__len__(self): 对应 len(obj)。__getitem__(self, key): 对应 obj[key] 的取值操作。__setitem__(self, key, value): 对应 obj[key] = value的赋值操作。__contains__(self, item): 对应 item in obj。
class Vector: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __eq__(self, other): return self.x == other.x and self.y == other.y def __str__(self): return f"Vector({self.x}, {self.y})"v1 = Vector(1, 2)v2 = Vector(3, 4)print(v1 + v2) # 调用 __add__: Vector(4, 6)print(v1 == v2) # 调用 __eq__: False
🔄 上下文管理方法
这两个方法让你的对象能够与 with 语句协同工作,实现资源的自动管理(如自动打开和关闭文件)。
__enter__(self): 在进入 with代码块时执行。__exit__(self, exc_type, exc_val, exc_tb): 在离开with代码块时执行,无论是否发生异常。
class MyContext: def __enter__(self): print("进入上下文") return self def __exit__(self, exc_type, exc_val, exc_tb): print("退出上下文") if exc_type: print(f"发生了异常: {exc_val}") return True # 返回True可以抑制异常# 输出:# 进入上下文# 发生了异常: division by zero# 退出上下文with MyContext(): print(1 / 0)
📞 可调用对象方法
实现 __call__ 方法可以让一个类的实例像函数一样被调用。
__call__(self, ...): 当你尝试调用一个实例obj()时触发。
class Multiplier: def __init__(self, factor): self.factor = factor def __call__(self, x): return x * self.factordouble = Multiplier(2)print(double(5)) # 调用 __call__: 10