python的特殊方法也叫魔法方法
·
🧙♂️ 为什么叫"魔术"?
因为当你写 a + b、len(obj)、str(obj) 等代码时,Python 会自动调用对应的魔术方法,就像变魔术一样!
✅ 常见魔术方法分类与示例
🔹 1. 对象创建与初始化
表格
| 方法 | 触发时机 | 说明 |
|---|---|---|
__new__(cls, ...) | 创建对象实例时 | 控制对象创建(很少重写) |
__init__(self, ...) | 对象初始化时 | 初始化属性(最常用) |
__del__(self) | 对象被销毁时 | 析构函数(慎用) |
class Person:
def __init__(self, name):
self.name = name
🔹 2. 字符串表示
表格
| 方法 | 触发时机 | 用途 |
|---|---|---|
__str__(self) | str(obj), print(obj) | 面向用户的可读字符串 |
__repr__(self) | repr(obj), 调试/交互式环境 | 面向开发者的精确表示(理想情况下应能 eval(repr(obj)) == obj) |
class Point:
def __init__(self, x, y):
self.x, self.y = x, y
def __str__(self):
return f"Point({self.x}, {self.y})"
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
p = Point(1, 2)
print(p) # Point(1, 2)
repr(p) # 'Point(x=1, y=2)'
🔹 3. 算术运算符
表格
| 方法 | 表达式 | 说明 |
|---|---|---|
__add__(self, other) | a + b | 加法 |
__sub__(self, other) | a - b | 减法 |
__mul__(self, other) | a * b | 乘法 |
__truediv__(self, other) | a / b | 真除法 |
__floordiv__(self, other) | a // b | 整除 |
__mod__(self, other) | a % b | 取模 |
__pow__(self, other) | a ** b | 幂运算 |
💡 还有反向方法(如
__radd__)用于1 + obj(当左边不是你的类时)
class Vector:
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
v1 = Vector(1, 2)
v2 = Vector(3, 4)
v3 = v1 + v2 # 自动调用 __add__
🔹 4. 比较运算符
表格
| 方法 | 表达式 |
|---|---|
__eq__(self, other) | a == b |
__ne__(self, other) | a != b |
__lt__(self, other) | a < b |
__le__(self, other) | a <= b |
__gt__(self, other) | a > b |
__ge__(self, other) | a >= b |
✅ 只需实现
__eq__和__lt__,再用@functools.total_ordering自动生成其他比较方法。
🔹 5. 容器/序列行为
表格
| 方法 | 触发时机 |
|---|---|
__len__(self) | len(obj) |
__getitem__(self, key) | obj[key] |
__setitem__(self, key, value) | obj[key] = value |
__delitem__(self, key) | del obj[key] |
__contains__(self, item) | item in obj |
__iter__(self) | for x in obj(返回迭代器) |
__next__(self) | 迭代器协议(配合 __iter__) |
class MyList:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return self.data[index]
mylist = MyList([1, 2, 3])
print(len(mylist)) # 3
print(mylist[0]) # 1
🔹 6. 调用对象像函数
表格
| 方法 | 触发时机 |
|---|---|
__call__(self, ...) | obj() |
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, x):
return x * self.factor
double = Multiplier(2)
print(double(5)) # 10
🔹 7. 上下文管理器(with 语句)
表格
| 方法 | 触发时机 |
|---|---|
__enter__(self) | 进入 with 块 |
__exit__(self, exc_type, exc_val, exc_tb) | 退出 with 块 |
class FileManager:
def __init__(self, filename):
self.filename = filename
def __enter__(self):
self.file = open(self.filename, 'w')
return self.file
def __exit__(self, *args):
self.file.close()
with FileManager('test.txt') as f:
f.write('hello')
# 自动关闭文件
🔹 8. 属性访问控制
表格
| 方法 | 触发时机 |
|---|---|
__getattr__(self, name) | 访问不存在的属性时 |
__getattribute__(self, name) | 所有属性访问(慎用!) |
__setattr__(self, name, value) | 设置属性时 |
__delattr__(self, name) | 删除属性时 |
class SafeDict:
def __init__(self):
self._data = {}
def __getattr__(self, name):
return self._data.get(name, "Not found")
d = SafeDict()
print(d.x) # "Not found"
🔹 9. 布尔值与真值测试
表格
| 方法 | 触发时机 |
|---|---|
__bool__(self) | bool(obj), if obj: |
__len__(self) | 如果没定义 __bool__,则用 len(obj) != 0 判断 |
class Truthy:
def __init__(self, value):
self.value = value
def __bool__(self):
return self.value > 0
t = Truthy(5)
if t: print("Positive!") # 打印
✅ 总结:常用魔术方法速查表
表格
| 功能 | 推荐实现的方法 |
|---|---|
| 打印友好 | __str__, __repr__ |
| 数学运算 | __add__, __mul__, … |
| 比较大小 | __eq__, __lt__ (+ @total_ordering) |
| 容器行为 | __len__, __getitem__, __iter__ |
| 函数调用 | __call__ |
| with 语句 | __enter__, __exit__ |
| 属性拦截 | __getattr__, __setattr__ |
⚠️ 注意事项:
- 不要滥用:只在需要自定义行为时才重写。
- 保持一致性:比如实现了
__eq__,通常也要实现__hash__(如果对象可哈希)。 - 使用
functools.total_ordering简化比较逻辑。 - 用
@property代替__get__/__set__大多数场景更简单。
更多推荐


所有评论(0)