欢迎光临
我们一直在努力

Python 数据模型核心双下划线方法

对象生命周期

方法触发时机返回值说明
__new__(cls, …) 创建实例时 新实例 类的构造器,在 __init__ 之前调用
__init__(self, …) 实例创建后 None 初始化实例,接收构造器参数
__del__(self) 垃圾回收时 None 析构器,通常不推荐手动实现

示例:

class MyClass:
def __new__(cls, *args, **kwargs):
print(f"__new__ called for {cls}")
return super().__new__(cls)

def __init__(self, value):
print(f"__init__ called with {value}")
self.value = value

def __del__(self):
print(f"__del__ called for {self}")

对象表示

方法触发时机返回值说明
__str__(self) str(obj) / print(obj) 字符串 对象的友好字符串表示
__repr__(self) repr(obj) / REPL 字符串 对象的开发者友好表示,通常可用来重建对象
__format__(self, format_spec) format(obj, spec) / f-string 字符串 格式化输出
__bytes__(self) bytes(obj) bytes 字节表示

示例:

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})"

def __format__(self, format_spec):
return f"<{self.x}, {self.y}>"

p = Point(3, 4)
print(p) # Point(3, 4) – __str__
print(repr(p) ) # Point(x=3, y=4) – __repr__
print(f"{p}" ) # Point(3, 4) – 默认使用 __str__

比较操作

方法触发时机返回值说明
__lt__(self, other) < bool 小于
__le__(self, other) <= bool 小于等于
__eq__(self, other) == bool 等于
__ne__(self, other) != bool 不等于
__gt__(self, other) > bool 大于
__ge__(self, other) >= bool 大于等于

使用 @functools.total_ordering 简化:

from functools import total_ordering

@total_ordering
class Person:
def __init__(self, age):
self.age = age

def __eq__(self, other):
if not isinstance(other, Person):
return NotImplemented
return self.age == other.age

def __lt__(self, other):
if not isinstance(other, Person):
return NotImplemented
return self.age < other.age

容器类型

容器大小与成员检测

方法触发时机返回值说明
__len__(self) len(obj) 整数 容器长度
__bool__(self) bool(obj) bool 真值测试
__contains__(self, item) item in obj bool 成员测试
__iter__(self) iter(obj) 迭代器 返回迭代器对象

元素访问

方法触发时机返回值说明
__getitem__(self, key) obj[key] 任意值 获取元素
__setitem__(self, key, value) obj[key] = value None 设置元素
__delitem__(self, key) del obj[key] None 删除元素
__missing__(self, key) key 不存在时 任意值 dict 子类的 fallback

示例:自定义列表:

class CustomList:
def __init__(self, items=None):
self._items = items or []

def __len__(self):
return len(self._items)

def __getitem__(self, index):
return self._items[index]

def __setitem__(self, index, value):
self._items[index] = value

def __delitem__(self, index):
del self._items[index]

def __contains__(self, item):
return item in self._items

def __iter__(self):
return iter(self._items)

可调用对象

方法触发时机返回值说明
__call__(self, *args, **kwargs) obj() 任意值 使对象像函数一样可调用

示例:

class Adder:
def __init__(self, n):
self.n = n

def __call__(self, x):
return self.n + x

add5 = Adder(5)
add5(10) # 返回 15

上下文管理

方法触发时机返回值说明
__enter__(self) with 块进入时 任意值 通常返回 self 或资源
__exit__(self, exc_type, exc_val, exc_tb) with 块退出时 bool/None 清理资源,可处理异常

示例:

class FileContext:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode

def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file

def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
return False # 不抑制异常

with FileContext('test.txt', 'w') as f:
f.write('Hello')

迭代器协议

方法触发时机返回值说明
__iter__(self) iter(obj) / for 循环 迭代器 返回自身(如果是迭代器)
__next__(self) next(iterator) 任意值 返回下一个元素,无元素时抛出 StopIteration

示例:自定义迭代器:

class CountDown:
def __init__(self, start):
self.current = start

def __iter__(self):
return self

def __next__(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1

for i in CountDown(5):
print(i) # 输出: 5, 4, 3, 2, 1

数值运算

一元运算

方法触发时机返回值说明
__neg__(self) -obj 数值 负号
__pos__(self) +obj 数值 正号
__abs__(self) abs(obj) 数值 绝对值
__invert__(self) ~obj 数值 按位取反

二元运算

方法触发时机返回值说明
__add__(self, other) + 数值 加法
__sub__(self, other) 数值 减法
__mul__(self, other) * 数值 乘法
__truediv__(self, other) / 数值 真除法
__floordiv__(self, other) // 数值 地板除
__mod__(self, other) % 数值 取模
__pow__(self, other, modulo) ** / pow() 数值 幂运算
__divmod__(self, other) divmod() 元组 商和余数

位运算

方法触发时机返回值说明
__and__(self, other) & 数值 按位与
__or__(self, other) | 数值 按位或
__xor__(self, other) ^ 数值 按位异或
__lshift__(self, other) << 数值 左移
__rshift__(self, other) >> 数值 右移

反向运算(右操作数类型不匹配时)

方法触发时机说明
__radd__(self, other) a + b 当 a 不支持 + 且 b 定义时
__rsub__(self, other) a – b 的反向
__rmul__(self, other) a * b 的反向
__rtruediv__(self, other) a / b 的反向
其他运算符同理

增量赋值

方法触发时机返回值说明
__iadd__(self, other) += 任意值 原地加法
__isub__(self, other) -= 任意值 原地减法
__imul__(self, other) *= 任意值 原地乘法
其他运算符同理

示例:复数实现:

class Complex:
def __init__(self, real, imag):
self.real = real
self.imag = imag

def __add__(self, other):
return Complex(self.real + other.real, self.imag + other.imag)

def __mul__(self, other):
return Complex(
self.real * other.real – self.imag * other.imag,
self.real * other.imag + self.imag * other.real
)

def __repr__(self):
return f"Complex({self.real}, {self.imag})"

类型转换

方法触发时机返回值说明
__int__(self) int(obj) 整数 转为整数
__float__(self) float(obj) 浮点数 转为浮点数
__complex__(self) complex(obj) 复数 转为复数
__index__(self) hex()/oct()/切片索引 整数 整数索引协议
__hash__(self) hash(obj) / 字典键 整数 哈希值

示例:

class Number:
def __init__(self, value):
self.value = value

def __int__(self):
return int(self.value)

def __float__(self):
return float(self.value)

def __hash__(self):
return hash(self.value)

num = Number(3.14)
int(num) # 3
float(num) # 3.14

属性访问

方法触发时机返回值说明
__getattr__(self, name) 属性不存在时 任意值 动态属性访问
__getattribute__(self, name) 任何属性访问时 任意值 属性访问拦截(慎用)
__setattr__(self, name, value) 设置属性时 None 拦截属性赋值
__delattr__(self, name) 删除属性时 None 拦截属性删除
__dir__(self) dir(obj) 列表 返回属性列表

示例:动态属性:

class DynamicAttrs:
def __init__(self):
self._data = {}

def __getattr__(self, name):
if name in self._data:
return self._data[name]
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")

def __setattr__(self, name, value):
if name.startswith('_'):
super().__setattr__(name, value)
else:
self._data[name] = value

obj = DynamicAttrs()
obj.name = "Alice"
print(obj.name) # Alice

序列协议

方法触发时机返回值说明
__reversed__(self) reversed(obj) 反向迭代器 反向遍历

示例:

class CountUp:
def __init__(self, max_val):
self.max_val = max_val

def __reversed__(self):
return iter(range(self.max_val, -1, -1))

list(reversed(CountUp(5))) # [5, 4, 3, 2, 1, 0]

核心设计原则

1. NotImplemented vs TypeError

def __eq__(self, other):
if isinstance(other, self.__class__):
return self.value == other.value
return NotImplemented # 让 Python 尝试 other.__eq__(self)

2. 避免无限递归

# ❌ 错误:递归
def __getattr__(self, name):
return self.name # 会再次触发 __getattr__

# ✅ 正确
def __getattr__(self, name):
return self._data[name]

3. __hash__ 与 __eq__ 的一致性

class Person:
def __init__(self, id):
self.id = id

def __eq__(self, other):
return self.id == other.id

def __hash__(self):
return hash(self.id) # 相等的对象必须有相等的 hash

常用组合示例

自定义字典(完整实现)

class CaseInsensitiveDict(dict):
def __setitem__(self, key, value):
super().__setitem__(key.lower(), value)

def __getitem__(self, key):
return super().__getitem__(key.lower())

def __contains__(self, key):
return super().__contains__(key.lower())

d = CaseInsensitiveDict()
d['Name'] = 'Alice'
print(d['name']) # Alice

范围对象(可切片)

class Range:
def __init__(self, start, end=None, step=1):
if end is None:
end = start
start = 0
self.start = start
self.end = end
self.step = step

def __len__(self):
return max(0, (self.end – self.start + self.step – 1) // self.step)

def __getitem__(self, index):
if isinstance(index, slice):
start, stop, step = index.indices(len(self))
return Range(self.start + start * self.step,
self.start + stop * self.step,
self.step * step)
if index < 0:
index += len(self)
if index < 0 or index >= len(self):
raise IndexError("range index out of range")
return self.start + index * self.step

def __iter__(self):
return iter(self[i] for i in range(len(self)))

list(Range(10)[2:7:2]) # [2, 4, 6]

实践建议

  • **按需实现 **:只实现你需要的方法,Python 会提供合理的默认行为
  • **返回 NotImplemented **:当操作不支持时,让 Python 尝试反向操作
  • **保持一致性 **:__eq__ 和 __hash__ 必须保持一致
  • **文档字符串 **:为魔法方法添加文档,解释其行为和参数
  • 类型检查:使用 isinstance() 而非 type() 进行类型检查
  • 参考资料

    • Python Data Model – Python 官方文档
    • Python Tricks: The Book – Dan Bader
    赞(0)
    未经允许不得转载:171主机测评 » Python 数据模型核心双下划线方法
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址