Python魔术方法与运算符重载一、什么是魔术方法魔术方法Magic Methods / Dunder Methods是Python中以双下划线开头和结尾的特殊方法。它们定义了对象在特定操作下的行为是Python数据模型的核心。二、对象创建与初始化class Vector:def __new__(cls, *args, **kwargs):创建实例在__init__之前调用instance super().__new__(cls)return instancedef __init__(self, x, y, z0):初始化实例self.x xself.y yself.z zdef __del__(self):析构方法垃圾回收时调用不推荐依赖passdef __repr__(self):开发者友好的字符串表示return fVector({self.x}, {self.y}, {self.z})def __str__(self):用户友好的字符串表示return f({self.x}, {self.y}, {self.z})v Vector(1, 2, 3)print(repr(v)) # Vector(1, 2, 3)print(str(v)) # (1, 2, 3)三、算术运算符import mathclass Vector:def __init__(self, x, y, z0):self.x xself.y yself.z z# 加法def __add__(self, other):if isinstance(other, Vector):return Vector(self.x other.x, self.y other.y, self.z other.z)return NotImplemented# 右加法当左操作数不支持时调用def __radd__(self, other):return self.__add__(other)# 增量加法def __iadd__(self, other):if isinstance(other, Vector):self.x other.xself.y other.yself.z other.zreturn selfreturn NotImplemented# 减法def __sub__(self, other):if isinstance(other, Vector):return Vector(self.x - other.x, self.y - other.y, self.z - other.z)return NotImplemented# 标量乘法def __mul__(self, scalar):if isinstance(scalar, (int, float)):return Vector(self.x * scalar, self.y * scalar, self.z * scalar)return NotImplementeddef __rmul__(self, scalar):return self.__mul__(scalar)# 除法def __truediv__(self, scalar):if isinstance(scalar, (int, float)):if scalar 0:raise ZeroDivisionError(向量不能除以零)return Vector(self.x / scalar, self.y / scalar, self.z / scalar)return NotImplemented# 取负def __neg__(self):return Vector(-self.x, -self.y, -self.z)# 绝对值向量长度def __abs__(self):return math.sqrt(self.x**2 self.y**2 self.z**2)def __repr__(self):return fVector({self.x}, {self.y}, {self.z})v1 Vector(1, 2, 3)v2 Vector(4, 5, 6)print(v1 v2) # Vector(5, 7, 9)print(v1 * 3) # Vector(3, 6, 9)print(3 * v1) # Vector(3, 6, 9)print(abs(v1)) # 3.7416...print(-v1) # Vector(-1, -2, -3)四、比较运算符from functools import total_orderingtotal_ordering # 只需定义__eq__和__lt__自动生成其他比较方法class Money:def __init__(self, amount, currencyCNY):self.amount round(amount, 2)self.currency currencydef __eq__(self, other):if isinstance(other, Money):self._check_currency(other)return self.amount other.amountreturn NotImplementeddef __lt__(self, other):if isinstance(other, Money):self._check_currency(other)return self.amount other.amountreturn NotImplementeddef __hash__(self):定义了__eq__就必须定义__hash__或设为None使其不可哈希return hash((self.amount, self.currency))def _check_currency(self, other):if self.currency ! other.currency:raise ValueError(f不能比较不同货币: {self.currency} vs {other.currency})def __repr__(self):return fMoney({self.amount}, {self.currency})m1 Money(100)m2 Money(200)print(m1 m2) # Trueprint(m1 m2) # False由total_ordering自动生成五、容器协议class Matrix:实现容器协议的矩阵类def __init__(self, rows):self._data [list(row) for row in rows]self._rows len(self._data)self._cols len(self._data[0]) if self._data else 0def __getitem__(self, key):支持索引和切片if isinstance(key, tuple):row, col keyreturn self._data[row][col]return self._data[key]def __setitem__(self, key, value):if isinstance(key, tuple):row, col keyself._data[row][col] valueelse:self._data[key] list(value)def __delitem__(self, key):del self._data[key]self._rows - 1def __len__(self):return self._rowsdef __contains__(self, value):支持 in 运算符return any(value in row for row in self._data)def __iter__(self):支持迭代return iter(self._data)def __reversed__(self):支持 reversed()return reversed(self._data)def __repr__(self):rows_str \n .join(str(row) for row in self._data)return fMatrix([\n {rows_str}\n])m Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])print(m[0, 1]) # 2print(m[1]) # [4, 5, 6]print(len(m)) # 3print(5 in m) # Truem[0, 0] 99print(m[0]) # [99, 2, 3]六、属性访问控制class DynamicConfig:动态配置对象def __init__(self, **kwargs):self._data kwargsdef __getattr__(self, name):属性不存在时调用if name.startswith(_):raise AttributeError(name)try:return self._data[name]except KeyError:raise AttributeError(f配置项 {name} 不存在)def __setattr__(self, name, value):设置属性时调用if name.startswith(_):super().__setattr__(name, value)else:self._data[name] valuedef __delattr__(self, name):删除属性时调用if name in self._data:del self._data[name]else:raise AttributeError(name)def __dir__(self):自定义dir()输出return list(self._data.keys())config DynamicConfig(hostlocalhost, port8080, debugTrue)print(config.host) # localhostconfig.timeout 30 # 动态添加del config.debug # 删除配置项七、可调用对象class Retry:可调用的重试器def __init__(self, max_retries3, exceptions(Exception,)):self.max_retries max_retriesself.exceptions exceptionsself.call_count 0def __call__(self, func):使实例可以作为装饰器使用import functoolsimport timefunctools.wraps(func)def wrapper(*args, **kwargs):for attempt in range(self.max_retries):try:self.call_count 1return func(*args, **kwargs)except self.exceptions as e:if attempt self.max_retries - 1:raisetime.sleep(2 ** attempt)return Nonereturn wrapperRetry(max_retries3, exceptions(ConnectionError,))def fetch_data(url):passclass Pipeline:可调用的数据处理管道def __init__(self, *steps):self.steps stepsdef __call__(self, data):result datafor step in self.steps:result step(result)return resultdef __or__(self, other):支持 | 运算符组合管道if callable(other):return Pipeline(*self.steps, other)return NotImplementedclean Pipeline(str.strip, str.lower, lambda s: s.replace( , _))print(clean( Hello World )) # hello_world八、上下文管理器协议class Timer:计时上下文管理器def __init__(self, label):self.label labelself.elapsed 0def __enter__(self):import timeself._start time.perf_counter()return selfdef __exit__(self, exc_type, exc_val, exc_tb):import timeself.elapsed time.perf_counter() - self._startprint(f{self.label}: {self.elapsed:.4f}s)return False # 不抑制异常with Timer(排序) as t:sorted(range(1000000, 0, -1))print(f耗时: {t.elapsed:.4f}s)九、数值类型协议class Fraction:分数类def __init__(self, numerator, denominator1):if denominator 0:raise ZeroDivisionError(分母不能为零)gcd math.gcd(abs(numerator), abs(denominator))sign -1 if (numerator * denominator 0) else 1self.numerator sign * abs(numerator) // gcdself.denominator abs(denominator) // gcddef __int__(self):return self.numerator // self.denominatordef __float__(self):return self.numerator / self.denominatordef __bool__(self):return self.numerator ! 0def __round__(self, ndigits0):return round(float(self), ndigits)def __format__(self, spec):if spec f:return f{float(self):.6f}elif spec mixed:whole self.numerator // self.denominatorremainder abs(self.numerator) % self.denominatorif remainder 0:return str(whole)if whole 0:return f{self.numerator}/{self.denominator}return f{whole} {remainder}/{self.denominator}return f{self.numerator}/{self.denominator}def __repr__(self):return fFraction({self.numerator}, {self.denominator})f Fraction(7, 3)print(int(f)) # 2print(float(f)) # 2.333...print(format(f, mixed)) # 2 1/3print(bool(Fraction(0))) # False十、实用技巧# __slots__ 限制属性class Point:__slots__ (x, y)def __init__(self, x, y):self.x xself.y y# __init_subclass__ 钩入子类创建class Plugin:_registry {}def __init_subclass__(cls, nameNone, **kwargs):super().__init_subclass__(**kwargs)cls._registry[name or cls.__name__] clsclass JSONPlugin(Plugin, namejson):pass# __class_getitem__ 支持泛型语法class Response:def __class_getitem__(cls, item):return type(fResponse[{item.__name__}], (cls,), {_type: item})# __missing__ 字典默认值class DefaultDict(dict):def __init__(self, factory):super().__init__()self.factory factorydef __missing__(self, key):value self.factory(key)self[key] valuereturn valuecache DefaultDict(lambda key: fcomputed_{key})print(cache[hello]) # computed_hello总结魔术方法是Python对象模型的基石。通过实现适当的魔术方法自定义类可以像内置类型一样自然地参与运算、迭代、比较等操作。关键原则是返回NotImplemented而非抛出TypeError让Python尝试反向操作以及保持运算符语义的一致性。
Python魔术方法与运算符重载
发布时间:2026/6/10 19:13:29
Python魔术方法与运算符重载一、什么是魔术方法魔术方法Magic Methods / Dunder Methods是Python中以双下划线开头和结尾的特殊方法。它们定义了对象在特定操作下的行为是Python数据模型的核心。二、对象创建与初始化class Vector:def __new__(cls, *args, **kwargs):创建实例在__init__之前调用instance super().__new__(cls)return instancedef __init__(self, x, y, z0):初始化实例self.x xself.y yself.z zdef __del__(self):析构方法垃圾回收时调用不推荐依赖passdef __repr__(self):开发者友好的字符串表示return fVector({self.x}, {self.y}, {self.z})def __str__(self):用户友好的字符串表示return f({self.x}, {self.y}, {self.z})v Vector(1, 2, 3)print(repr(v)) # Vector(1, 2, 3)print(str(v)) # (1, 2, 3)三、算术运算符import mathclass Vector:def __init__(self, x, y, z0):self.x xself.y yself.z z# 加法def __add__(self, other):if isinstance(other, Vector):return Vector(self.x other.x, self.y other.y, self.z other.z)return NotImplemented# 右加法当左操作数不支持时调用def __radd__(self, other):return self.__add__(other)# 增量加法def __iadd__(self, other):if isinstance(other, Vector):self.x other.xself.y other.yself.z other.zreturn selfreturn NotImplemented# 减法def __sub__(self, other):if isinstance(other, Vector):return Vector(self.x - other.x, self.y - other.y, self.z - other.z)return NotImplemented# 标量乘法def __mul__(self, scalar):if isinstance(scalar, (int, float)):return Vector(self.x * scalar, self.y * scalar, self.z * scalar)return NotImplementeddef __rmul__(self, scalar):return self.__mul__(scalar)# 除法def __truediv__(self, scalar):if isinstance(scalar, (int, float)):if scalar 0:raise ZeroDivisionError(向量不能除以零)return Vector(self.x / scalar, self.y / scalar, self.z / scalar)return NotImplemented# 取负def __neg__(self):return Vector(-self.x, -self.y, -self.z)# 绝对值向量长度def __abs__(self):return math.sqrt(self.x**2 self.y**2 self.z**2)def __repr__(self):return fVector({self.x}, {self.y}, {self.z})v1 Vector(1, 2, 3)v2 Vector(4, 5, 6)print(v1 v2) # Vector(5, 7, 9)print(v1 * 3) # Vector(3, 6, 9)print(3 * v1) # Vector(3, 6, 9)print(abs(v1)) # 3.7416...print(-v1) # Vector(-1, -2, -3)四、比较运算符from functools import total_orderingtotal_ordering # 只需定义__eq__和__lt__自动生成其他比较方法class Money:def __init__(self, amount, currencyCNY):self.amount round(amount, 2)self.currency currencydef __eq__(self, other):if isinstance(other, Money):self._check_currency(other)return self.amount other.amountreturn NotImplementeddef __lt__(self, other):if isinstance(other, Money):self._check_currency(other)return self.amount other.amountreturn NotImplementeddef __hash__(self):定义了__eq__就必须定义__hash__或设为None使其不可哈希return hash((self.amount, self.currency))def _check_currency(self, other):if self.currency ! other.currency:raise ValueError(f不能比较不同货币: {self.currency} vs {other.currency})def __repr__(self):return fMoney({self.amount}, {self.currency})m1 Money(100)m2 Money(200)print(m1 m2) # Trueprint(m1 m2) # False由total_ordering自动生成五、容器协议class Matrix:实现容器协议的矩阵类def __init__(self, rows):self._data [list(row) for row in rows]self._rows len(self._data)self._cols len(self._data[0]) if self._data else 0def __getitem__(self, key):支持索引和切片if isinstance(key, tuple):row, col keyreturn self._data[row][col]return self._data[key]def __setitem__(self, key, value):if isinstance(key, tuple):row, col keyself._data[row][col] valueelse:self._data[key] list(value)def __delitem__(self, key):del self._data[key]self._rows - 1def __len__(self):return self._rowsdef __contains__(self, value):支持 in 运算符return any(value in row for row in self._data)def __iter__(self):支持迭代return iter(self._data)def __reversed__(self):支持 reversed()return reversed(self._data)def __repr__(self):rows_str \n .join(str(row) for row in self._data)return fMatrix([\n {rows_str}\n])m Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]])print(m[0, 1]) # 2print(m[1]) # [4, 5, 6]print(len(m)) # 3print(5 in m) # Truem[0, 0] 99print(m[0]) # [99, 2, 3]六、属性访问控制class DynamicConfig:动态配置对象def __init__(self, **kwargs):self._data kwargsdef __getattr__(self, name):属性不存在时调用if name.startswith(_):raise AttributeError(name)try:return self._data[name]except KeyError:raise AttributeError(f配置项 {name} 不存在)def __setattr__(self, name, value):设置属性时调用if name.startswith(_):super().__setattr__(name, value)else:self._data[name] valuedef __delattr__(self, name):删除属性时调用if name in self._data:del self._data[name]else:raise AttributeError(name)def __dir__(self):自定义dir()输出return list(self._data.keys())config DynamicConfig(hostlocalhost, port8080, debugTrue)print(config.host) # localhostconfig.timeout 30 # 动态添加del config.debug # 删除配置项七、可调用对象class Retry:可调用的重试器def __init__(self, max_retries3, exceptions(Exception,)):self.max_retries max_retriesself.exceptions exceptionsself.call_count 0def __call__(self, func):使实例可以作为装饰器使用import functoolsimport timefunctools.wraps(func)def wrapper(*args, **kwargs):for attempt in range(self.max_retries):try:self.call_count 1return func(*args, **kwargs)except self.exceptions as e:if attempt self.max_retries - 1:raisetime.sleep(2 ** attempt)return Nonereturn wrapperRetry(max_retries3, exceptions(ConnectionError,))def fetch_data(url):passclass Pipeline:可调用的数据处理管道def __init__(self, *steps):self.steps stepsdef __call__(self, data):result datafor step in self.steps:result step(result)return resultdef __or__(self, other):支持 | 运算符组合管道if callable(other):return Pipeline(*self.steps, other)return NotImplementedclean Pipeline(str.strip, str.lower, lambda s: s.replace( , _))print(clean( Hello World )) # hello_world八、上下文管理器协议class Timer:计时上下文管理器def __init__(self, label):self.label labelself.elapsed 0def __enter__(self):import timeself._start time.perf_counter()return selfdef __exit__(self, exc_type, exc_val, exc_tb):import timeself.elapsed time.perf_counter() - self._startprint(f{self.label}: {self.elapsed:.4f}s)return False # 不抑制异常with Timer(排序) as t:sorted(range(1000000, 0, -1))print(f耗时: {t.elapsed:.4f}s)九、数值类型协议class Fraction:分数类def __init__(self, numerator, denominator1):if denominator 0:raise ZeroDivisionError(分母不能为零)gcd math.gcd(abs(numerator), abs(denominator))sign -1 if (numerator * denominator 0) else 1self.numerator sign * abs(numerator) // gcdself.denominator abs(denominator) // gcddef __int__(self):return self.numerator // self.denominatordef __float__(self):return self.numerator / self.denominatordef __bool__(self):return self.numerator ! 0def __round__(self, ndigits0):return round(float(self), ndigits)def __format__(self, spec):if spec f:return f{float(self):.6f}elif spec mixed:whole self.numerator // self.denominatorremainder abs(self.numerator) % self.denominatorif remainder 0:return str(whole)if whole 0:return f{self.numerator}/{self.denominator}return f{whole} {remainder}/{self.denominator}return f{self.numerator}/{self.denominator}def __repr__(self):return fFraction({self.numerator}, {self.denominator})f Fraction(7, 3)print(int(f)) # 2print(float(f)) # 2.333...print(format(f, mixed)) # 2 1/3print(bool(Fraction(0))) # False十、实用技巧# __slots__ 限制属性class Point:__slots__ (x, y)def __init__(self, x, y):self.x xself.y y# __init_subclass__ 钩入子类创建class Plugin:_registry {}def __init_subclass__(cls, nameNone, **kwargs):super().__init_subclass__(**kwargs)cls._registry[name or cls.__name__] clsclass JSONPlugin(Plugin, namejson):pass# __class_getitem__ 支持泛型语法class Response:def __class_getitem__(cls, item):return type(fResponse[{item.__name__}], (cls,), {_type: item})# __missing__ 字典默认值class DefaultDict(dict):def __init__(self, factory):super().__init__()self.factory factorydef __missing__(self, key):value self.factory(key)self[key] valuereturn valuecache DefaultDict(lambda key: fcomputed_{key})print(cache[hello]) # computed_hello总结魔术方法是Python对象模型的基石。通过实现适当的魔术方法自定义类可以像内置类型一样自然地参与运算、迭代、比较等操作。关键原则是返回NotImplemented而非抛出TypeError让Python尝试反向操作以及保持运算符语义的一致性。