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 __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 4)
v2 = Vector(3, 1)
print(v1 + v2) # 输出: Vector(5, 5)
核心原理与工作机制
Python通过方法查找协议实现魔术方法的调用。当解释器遇到特殊操作时(如+
、in
等),会按照以下顺序查找:
1. 对象实例的__dict__
2. 对象类的__dict__
3. 父类继承链
名称修饰规则确保这些方法不会被意外覆盖。例如__len__
在类定义时会被转换为_ClassName__len
的形式存储。
常用魔术方法分类
对象生命周期控制
__new__
: 控制实例创建过程__init__
: 对象初始化__del__
: 对象销毁前清理
class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
数值运算方法族
__add__
/__sub__
: 加减运算__mul__
/__matmul__
: 乘/矩阵乘__abs__
: 绝对值运算
容器类型模拟
__len__
: 返回容器长度__getitem__
: 实现索引访问__contains__
: 实现in
操作符
class CustomRange:
def __init__(self, start, end):
self.start = start
self.end = end
def __len__(self):
return self.end - self.start
def __getitem__(self, index):
if index >= len(self):
raise IndexError
return self.start + index
def __contains__(self, item):
return self.start <= item < self.end
cr = CustomRange(5, 10)
print(7 in cr) # True
print(cr[2]) # 7
高级应用场景
上下文管理器协议
__enter__
和__exit__
方法构成上下文管理协议的基础:
class DatabaseConnection:
def __enter__(self):
self.conn = create_connection()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
self.conn.close()
if exc_type is not None:
logger.error(f"Error occurred: {exc_val}")
描述符协议
通过__get__
、__set__
和__delete__
实现属性访问控制:
class ValidatedAttribute:
def __init__(self, validator):
self.validator = validator
self._name = None
def __set_name__(self, owner, name):
self._name = name
def __get__(self, instance, owner):
return instance.__dict__[self._name]
def __set__(self, instance, value):
if not self.validator(value):
raise ValueError(f"Invalid value for {self._name}")
instance.__dict__[self._name] = value
性能优化与最佳实践
- 惰性计算模式:通过
__getattr__
延迟加载大型资源 - 避免递归陷阱:在
__setattr__
中谨慎使用属性赋值 - 类型提示支持:为魔术方法添加适当的类型注解
class LazyLoader:
def __init__(self, loader_func):
self.loader_func = loader_func
self._loaded = False
self._data = None
def __getattr__(self, name):
if not self._loaded:
self._data = self.loader_func()
self._loaded = True
return getattr(self._data, name)
行业实践参考
主流框架对魔术方法的典型应用:
– Django模型中的__str__
用于admin界面显示
– NumPy数组重载所有数值运算方法
– SQLAlchemy使用描述符协议实现ORM映射
性能基准测试显示,正确使用魔术方法相比普通方法调用仅有约5-10%的性能开销,在大多数应用场景中可以忽略不计。
常见陷阱与解决方案
- 无限递归问题:
class BadExample:
def __setattr__(self, name, value):
self.name = value # 错误!会导致无限递归
# 正确做法
def __setattr__(self, name, value):
super().__setattr__(name, value)
- 运算符重载冲突:
- 当重载
__eq__
时必须同时重载__hash__
- 非对称运算符(如
__lt__
)应返回NotImplemented
以支持反向操作
- 继承链问题:
- 使用
super()
确保父类方法被正确调用 - 在多重继承场景中注意方法解析顺序(MRO)