Python 中常用的魔法方法
魔法方法(Magic Methods),也称为特殊方法(Special Methods)或双下方法(Dunder Methods),是 Python 中由双下划线(__)包围的特殊方法。它们允许类定义自己的行为,使其能够与 Python 的内置操作符和函数一起工作。
一、基本魔法方法
1. 对象生命周期相关
-
__new__(cls, [...]):实例创建时第一个调用的方法 -
__init__(self, [...]):构造器,初始化实例 -
__del__(self):析构器,对象销毁时调用
class MyClass:
def __new__(cls, *args, **kwargs):
print("Creating instance")
instance = super().__new__(cls)
return instance
def __init__(self, value):
print("Initializing instance")
self.value = value
def __del__(self):
print("Instance is being destroyed")
obj = MyClass(10) # 输出: Creating instance 和 Initializing instance
del obj # 输出: Instance is being destroyed
2. 字符串表示
-
__str__(self):str(obj)和print(obj)时调用 -
__repr__(self):repr(obj)和交互式解释器中直接显示对象时调用
class Point:
def __init__(self, x, y):
self.x = x
self.y = 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)
print(repr(p)) # 输出: Point(x=1, y=2)
二、容器类型魔法方法
1. 序列和映射方法
-
__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时调用
class MyList:
def __init__(self, data):
self.data = list(data)
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
def __delitem__(self, index):
del self.data[index]
def __contains__(self, item):
return item in self.data
ml = MyList([1, 2, 3])
print(len(ml)) # 3
print(ml[1]) # 2
print(3 in ml) # True
2. 迭代器协议
-
__iter__(self):iter(obj)或for x in obj时调用 -
__next__(self):迭代时获取下一个值
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
else:
self.current -= 1
return self.current + 1
for num in CountDown(3):
print(num) # 输出: 3, 2, 1
三、数值运算魔法方法
1. 基本算术运算
-
__add__(self, other):+运算 -
__sub__(self, other):-运算 -
__mul__(self, other):*运算 -
__truediv__(self, other):/运算 -
__floordiv__(self, other)://运算 -
__mod__(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 __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 4)
v2 = Vector(1, 3)
print(v1 + v2) # Vector(3, 7)
print(v1 * 3) # Vector(6, 12)
2. 比较运算
-
__eq__(self, other):==运算 -
__ne__(self, other):!=运算 -
__lt__(self, other):<运算 -
__le__(self, other):<=运算 -
__gt__(self, other):>运算 -
__ge__(self, other):>=运算
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
def __eq__(self, other):
return self.celsius == other.celsius
def __lt__(self, other):
return self.celsius < other.celsius
def __str__(self):
return f"{self.celsius}°C"
t1 = Temperature(20)
t2 = Temperature(30)
print(t1 < t2) # True
print(t1 == t2) # False
四、上下文管理
-
__enter__(self):进入with代码块时调用 -
__exit__(self, exc_type, exc_val, exc_tb):退出with代码块时调用
class Timer:
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
self.end = time.time()
print(f"Elapsed time: {self.end - self.start:.2f} seconds")
with Timer():
# 执行一些代码
sum(range(1000000))
五、属性访问控制
-
__getattr__(self, name):访问不存在的属性时调用 -
__setattr__(self, name, value):设置属性时调用 -
__delattr__(self, name):删除属性时调用 -
__getattribute__(self, name):访问任何属性时调用(慎用)
class Restricted:
def __init__(self):
self.allowed = "This is allowed"
def __getattr__(self, name):
return f"Access to '{name}' is not allowed"
def __setattr__(self, name, value):
if name == 'allowed':
super().__setattr__(name, value)
else:
print(f"Cannot set attribute '{name}'")
r = Restricted()
print(r.allowed) # This is allowed
print(r.forbidden) # Access to 'forbidden' is not allowed
r.forbidden = 123 # Cannot set attribute 'forbidden'
六、调用模拟
-
__call__(self, [...]):使实例可以像函数一样被调用
class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return self.n + x
add5 = Adder(5)
print(add5(3)) # 8
七、其他实用魔法方法
-
__slots__:限制实例属性,节省内存 -
__hash__(self):hash(obj)时调用 -
__bool__(self):bool(obj)时调用 -
__dir__(self):dir(obj)时调用
class Limited:
__slots__ = ['a', 'b'] # 只能有a和b两个属性
def __init__(self, a, b):
self.a = a
self.b = b
def __bool__(self):
return bool(self.a or self.b)
l = Limited(0, 1)
print(bool(l)) # True
最佳实践
-
仅在需要时实现魔法方法:不要过度使用,只在需要特殊行为时实现
-
保持一致性:实现比较操作时,应实现全套比较方法
-
遵循约定:如
__eq__应该与__hash__一起实现 -
文档化:为魔法方法添加文档字符串,说明其行为
魔法方法是 Python 强大灵活性的重要组成部分,合理使用可以使你的类更加 Pythonic 和易用。

浙公网安备 33010602011771号