目录
什么是魔法方法
魔法方法(Magic Methods)也称为双下划线方法(Dunder Methods),是Python中以双下划线开头和结尾的特殊方法,如 __init__、__str__ 等。这些方法允许我们自定义类的行为,使其支持Python的内置操作。
特点:
- 以双下划线
__开头和结尾 - 不需要直接调用,会被Python解释器自动调用
- 让自定义对象支持内置函数和运算符
对象的生命周期
__new__(cls, *args, **kwargs)
创建实例的第一步,在 __init__ 之前调用。
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self, value):
self.value = value
# 测试单例模式
s1 = Singleton(1)
s2 = Singleton(2)
print(s1 is s2) # True
print(s1.value) # 2
__init__(self, *args, **kwargs)
初始化实例,最常用的魔法方法。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("Alice", 25)
__del__(self)
对象销毁时调用的析构方法。
class FileHandler:
def __init__(self, filename):
self.file = open(filename, 'w')
def __del__(self):
if hasattr(self, 'file'):
self.file.close()
print(f"文件已关闭")
注意: 不建议依赖 __del__,因为调用时机不确定。使用上下文管理器更可靠。
属性访问
__getattr__(self, name)
访问不存在的属性时调用。
class DynamicAttrs:
def __init__(self):
self.existing = "I exist"
def __getattr__(self, name):
return f"属性 '{name}' 不存在,返回默认值"
obj = DynamicAttrs()
print(obj.existing) # I exist
print(obj.nonexistent) # 属性 'nonexistent' 不存在,返回默认值
__getattribute__(self, name)
访问任何属性时都会调用(包括存在的属性)。
class LoggedAccess:
def __init__(self):
self.value = 42
def __getattribute__(self, name):
print(f"访问属性: {name}")
return super().__getattribute__(name)
obj = LoggedAccess()
print(obj.value)
# 输出:
# 访问属性: value
# 42
注意: 使用 __getattribute__ 要小心无限递归,必须使用 super().__getattribute__().
__setattr__(self, name, value)
设置属性时调用。
class ValidatedAttrs:
def __setattr__(self, name, value):
if name == 'age' and (value < 0 or value > 150):
raise ValueError("年龄必须在0-150之间")
super().__setattr__(name, value)
person = ValidatedAttrs()
person.age = 25 # OK
# person.age = 200 # ValueError
__delattr__(self, name)
删除属性时调用。
class ProtectedAttrs:
def __init__(self):
self.public = "可删除"
self._protected = "受保护"
def __delattr__(self, name):
if name.startswith('_'):
raise AttributeError(f"不能删除受保护的属性: {name}")
super().__delattr__(name)
obj = ProtectedAttrs()
del obj.public # OK
# del obj._protected # AttributeError
__dir__(self)
自定义 dir() 函数的输出。
class CustomDir:
def __init__(self):
self.x = 1
self.y = 2
def __dir__(self):
return ['x', 'y', 'custom_method']
obj = CustomDir()
print(dir(obj)) # ['custom_method', 'x', 'y']
字符串表示
__str__(self)
定义 str() 和 print() 的输出,面向用户。
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
return f"《{self.title}》 by {self.author}"
book = Book("Python编程", "张三")
print(book) # 《Python编程》 by 张三
__repr__(self)
定义对象的"官方"字符串表示,面向开发者。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point({self.x}, {self.y})"
def __str__(self):
return f"({self.x}, {self.y})"
p = Point(3, 4)
print(str(p)) # (3, 4)
print(repr(p)) # Point(3, 4)
print([p]) # [Point(3, 4)] # 列表使用__repr__
__format__(self, format_spec)
自定义字符串格式化。
class Currency:
def __init__(self, amount):
self.amount = amount
def __format__(self, format_spec):
if format_spec == 'usd':
return f"${self.amount:.2f}"
elif format_spec == 'cny':
return f"¥{self.amount:.2f}"
return str(self.amount)
money = Currency(1234.5)
print(f"{money:usd}") # $1234.50
print(f"{money:cny}") # ¥1234.50
__bytes__(self)
定义 bytes() 的行为。
class ByteString:
def __init__(self, text):
self.text = text
def __bytes__(self):
return self.text.encode('utf-8')
obj = ByteString("Hello")
print(bytes(obj)) # b'Hello'
比较运算符
__eq__(self, other) - 等于 (==)
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
if not isinstance(other, Person):
return False
return self.name == other.name and self.age == other.age
p1 = Person("Alice", 25)
p2 = Person("Alice", 25)
print(p1 == p2) # True
__ne__(self, other) - 不等于 (!=)
class Number:
def __init__(self, value):
self.value = value
def __ne__(self, other):
return self.value != other.value
__lt__(self, other) - 小于 (<)
__le__(self, other) - 小于等于 (<=)
__gt__(self, other) - 大于 (>)
__ge__(self, other) - 大于等于 (>=)
from functools import total_ordering
@total_ordering # 只需定义 __eq__ 和一个比较方法,自动生成其他
class Version:
def __init__(self, major, minor, patch):
self.major = major
self.minor = minor
self.patch = patch
def __eq__(self, other):
return (self.major, self.minor, self.patch) == \
(other.major, other.minor, other.patch)
def __lt__(self, other):
return (self.major, self.minor, self.patch) < \
(other.major, other.minor, other.patch)
v1 = Version(1, 2, 3)
v2 = Version(1, 3, 0)
print(v1 < v2) # True
print(v1 <= v2) # True (自动生成)
print(v1 > v2) # False (自动生成)
数值运算符
算术运算符
__add__(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 __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
__sub__(self, other) - 减法 (-)
__mul__(self, other) - 乘法 (*)
__truediv__(self, other) - 真除法 (/)
__floordiv__(self, other) - 整除 (//)
__mod__(self, other) - 取模 (%)
__pow__(self, other) - 幂运算 (**)
class ComplexNumber:
def __init__(self, real, imag):
self.real = real
self.imag = imag
def __add__(self, other):
return ComplexNumber(
self.real + other.real,
self.imag + other.imag
)
def __mul__(self, other):
# (a+bi)(c+di) = (ac-bd) + (ad+bc)i
return ComplexNumber(
self.real * other.real - self.imag * other.imag,
self.real * other.imag + self.imag * other.real
)
def __repr__(self):
return f"{self.real}+{self.imag}i"
c1 = ComplexNumber(1, 2)
c2 = ComplexNumber(3, 4)
print(c1 + c2) # 4+6i
print(c1 * c2) # -5+10i
反射运算符 (右侧运算)
__radd__(self, other) - 右加法
当左操作数不支持运算时调用右操作数的反射方法。
class MyInt:
def __init__(self, value):
self.value = value
def __radd__(self, other):
print(f"调用 __radd__: {other} + MyInt({self.value})")
return other + self.value
obj = MyInt(10)
result = 5 + obj # int 不支持 + MyInt,调用 MyInt.__radd__
print(result) # 15
同理还有: __rsub__, __rmul__, __rtruediv__, __rfloordiv__, __rmod__, __rpow__
增强赋值运算符
__iadd__(self, other) - 加法赋值 (+=)
class Counter:
def __init__(self, value=0):
self.value = value
def __iadd__(self, other):
self.value += other
return self # 必须返回self
def __repr__(self):
return f"Counter({self.value})"
c = Counter(10)
c += 5
print(c) # Counter(15)
同理还有: __isub__, __imul__, __itruediv__, __ifloordiv__, __imod__, __ipow__
一元运算符
__neg__(self) - 负号 (-)
__pos__(self) - 正号 (+)
__abs__(self) - 绝对值 abs()
__invert__(self) - 按位取反 (~)
class SignedNumber:
def __init__(self, value):
self.value = value
def __neg__(self):
return SignedNumber(-self.value)
def __pos__(self):
return SignedNumber(+self.value)
def __abs__(self):
return SignedNumber(abs(self.value))
def __repr__(self):
return f"SignedNumber({self.value})"
n = SignedNumber(-5)
print(-n) # SignedNumber(5)
print(+n) # SignedNumber(-5)
print(abs(n)) # SignedNumber(5)
位运算符
__and__(self, other) - 按位与 (&)
__or__(self, other) - 按位或 (|)
__xor__(self, other) - 按位异或 (^)
__lshift__(self, other) - 左移 (<<)
__rshift__(self, other) - 右移 (>>)
class BitSet:
def __init__(self, value):
self.value = value
def __and__(self, other):
return BitSet(self.value & other.value)
def __or__(self, other):
return BitSet(self.value | other.value)
def __repr__(self):
return f"BitSet({bin(self.value)})"
b1 = BitSet(0b1010)
b2 = BitSet(0b1100)
print(b1 & b2) # BitSet(0b1000)
print(b1 | b2) # BitSet(0b1110)
类型转换
__int__(self) - int()
__float__(self) - float()
__complex__(self) - complex()
__bool__(self) - bool()
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
def __int__(self):
return int(self.celsius)
def __float__(self):
return float(self.celsius)
def __bool__(self):
return self.celsius != 0
temp = Temperature(36.5)
print(int(temp)) # 36
print(float(temp)) # 36.5
print(bool(temp)) # True
__round__(self, n=0) - round()
__floor__(self) - math.floor()
__ceil__(self) - math.ceil()
__trunc__(self) - math.trunc()
import math
class Decimal:
def __init__(self, value):
self.value = value
def __round__(self, n=0):
return round(self.value, n)
def __floor__(self):
return math.floor(self.value)
def __ceil__(self):
return math.ceil(self.value)
d = Decimal(3.7)
print(round(d)) # 4
print(math.floor(d)) # 3
print(math.ceil(d)) # 4
容器类型
__len__(self) - len()
返回容器的长度。
class Playlist:
def __init__(self):
self.songs = []
def add(self, song):
self.songs.append(song)
def __len__(self):
return len(self.songs)
playlist = Playlist()
playlist.add("Song 1")
playlist.add("Song 2")
print(len(playlist)) # 2
__getitem__(self, key) - 索引访问 []
class MyList:
def __init__(self, items):
self.items = items
def __getitem__(self, index):
# 支持负索引
if isinstance(index, int):
return self.items[index]
# 支持切片
elif isinstance(index, slice):
return MyList(self.items[index])
lst = MyList([1, 2, 3, 4, 5])
print(lst[0]) # 1
print(lst[-1]) # 5
print(lst[1:3]) # MyList([2, 3])
__setitem__(self, key, value) - 索引赋值
class Grid:
def __init__(self, rows, cols):
self.data = [[0] * cols for _ in range(rows)]
def __setitem__(self, pos, value):
row, col = pos
self.data[row][col] = value
def __getitem__(self, pos):
row, col = pos
return self.data[row][col]
grid = Grid(3, 3)
grid[1, 2] = 5
print(grid[1, 2]) # 5
__delitem__(self, key) - 删除元素
class RemovableList:
def __init__(self, items):
self.items = list(items)
def __delitem__(self, index):
del self.items[index]
def __repr__(self):
return f"RemovableList({self.items})"
lst = RemovableList([1, 2, 3, 4])
del lst[1]
print(lst) # RemovableList([1, 3, 4])
__contains__(self, item) - in 运算符
class Team:
def __init__(self):
self.members = set()
def add_member(self, name):
self.members.add(name)
def __contains__(self, name):
return name in self.members
team = Team()
team.add_member("Alice")
print("Alice" in team) # True
print("Bob" in team) # False
__iter__(self) - 迭代器
返回一个迭代器对象。
class Countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
self.current = self.start
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1
for num in Countdown(5):
print(num) # 5, 4, 3, 2, 1
__reversed__(self) - reversed()
class ReversibleList:
def __init__(self, items):
self.items = items
def __reversed__(self):
return iter(reversed(self.items))
lst = ReversibleList([1, 2, 3, 4])
for item in reversed(lst):
print(item) # 4, 3, 2, 1
可调用对象
__call__(self, *args, **kwargs)
使对象可以像函数一样被调用。
class Multiplier:
def __init__(self, factor):
self.factor = factor
def __call__(self, x):
return x * self.factor
double = Multiplier(2)
triple = Multiplier(3)
print(double(5)) # 10
print(triple(5)) # 15
实际应用:
class Counter:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self.count
counter = Counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3
上下文管理器
__enter__(self) 和 __exit__(self, exc_type, exc_val, exc_tb)
实现 with 语句支持。
class FileManager:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
print(f"打开文件: {self.filename}")
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
print(f"关闭文件: {self.filename}")
if self.file:
self.file.close()
# 返回False表示不抑制异常,返回True表示抑制异常
return False
with FileManager('test.txt', 'w') as f:
f.write('Hello World')
异常处理:
class ExceptionHandler:
def __enter__(self):
print("进入上下文")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type is not None:
print(f"捕获异常: {exc_type.__name__}: {exc_val}")
return True # 抑制异常
print("正常退出")
return False
with ExceptionHandler():
print("执行代码")
raise ValueError("出错了")
print("继续执行") # 会执行,因为异常被抑制
描述符
__get__(self, instance, owner)
__set__(self, instance, value)
__delete__(self, instance)
描述符是实现了描述符协议的对象,用于自定义属性访问。
class ValidatedAttribute:
def __init__(self, min_value=None, max_value=None):
self.min_value = min_value
self.max_value = max_value
self.data = {}
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
if instance is None:
return self
return self.data.get(id(instance))
def __set__(self, instance, value):
if self.min_value is not None and value < self.min_value:
raise ValueError(f"{self.name} 不能小于 {self.min_value}")
if self.max_value is not None and value > self.max_value:
raise ValueError(f"{self.name} 不能大于 {self.max_value}")
self.data[id(instance)] = value
def __delete__(self, instance):
del self.data[id(instance)]
class Person:
age = ValidatedAttribute(min_value=0, max_value=150)
def __init__(self, age):
self.age = age
person = Person(25)
print(person.age) # 25
person.age = 30 # OK
# person.age = 200 # ValueError
property 装饰器的实现:
class MyProperty:
def __init__(self, fget=None, fset=None, fdel=None):
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, instance, owner):
if instance is None:
return self
if self.fget is None:
raise AttributeError("无法读取")
return self.fget(instance)
def __set__(self, instance, value):
if self.fset is None:
raise AttributeError("无法设置")
self.fset(instance, value)
def __delete__(self, instance):
if self.fdel is None:
raise AttributeError("无法删除")
self.fdel(instance)
class Circle:
def __init__(self, radius):
self._radius = radius
def get_radius(self):
return self._radius
def set_radius(self, value):
if value < 0:
raise ValueError("半径不能为负")
self._radius = value
radius = MyProperty(get_radius, set_radius)
c = Circle(5)
print(c.radius) # 5
c.radius = 10 # OK
__set_name__(self, owner, name)
在描述符被赋值给类属性时自动调用。
class NamedDescriptor:
def __set_name__(self, owner, name):
self.name = name
self.private_name = f'_{name}'
def __get__(self, instance, owner):
if instance is None:
return self
return getattr(instance, self.private_name)
def __set__(self, instance, value):
print(f"设置 {self.name} = {value}")
setattr(instance, self.private_name, value)
class MyClass:
attr = NamedDescriptor() # 自动获取名称 'attr'
def __init__(self, value):
self.attr = value
obj = MyClass(42)
print(obj.attr) # 42
其他魔法方法
__hash__(self)
返回对象的哈希值,用于字典键和集合。
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __hash__(self):
return hash((self.x, self.y))
p1 = Point(1, 2)
p2 = Point(1, 2)
print(hash(p1) == hash(p2)) # True
# 可以用作字典键
points = {p1: "第一个点"}
print(points[p2]) # 第一个点
注意: 如果定义了 __eq__,也应该定义 __hash__,否则对象不可哈希。
__index__(self)
将对象转换为整数索引。
class IntLike:
def __init__(self, value):
self.value = value
def __index__(self):
return self.value
idx = IntLike(2)
lst = [10, 20, 30, 40]
print(lst[idx]) # 30
print(bin(idx)) # '0b10'
__sizeof__(self)
返回对象占用的内存大小(字节)。
import sys
class MyClass:
def __init__(self, data):
self.data = data
def __sizeof__(self):
return super().__sizeof__() + sys.getsizeof(self.data)
obj = MyClass([1, 2, 3, 4, 5])
print(sys.getsizeof(obj)) # 返回自定义的大小
__copy__(self) 和 __deepcopy__(self, memo)
自定义拷贝行为。
import copy
class MyList:
def __init__(self, items):
self.items = items
def __copy__(self):
print("执行浅拷贝")
return MyList(self.items)
def __deepcopy__(self, memo):
print("执行深拷贝")
return MyList(copy.deepcopy(self.items, memo))
original = MyList([[1, 2], [3, 4]])
shallow = copy.copy(original)
deep = copy.deepcopy(original)
__reduce__(self) 和 __reduce_ex__(self, protocol)
用于 pickle 序列化。
import pickle
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __reduce__(self):
return (
self.__class__,
(self.name, self.age)
)
person = Person("Alice", 25)
serialized = pickle.dumps(person)
restored = pickle.loads(serialized)
print(restored.name, restored.age) # Alice 25
__missing__(self, key)
在字典子类中,当键不存在时调用。
class DefaultDict(dict):
def __init__(self, default_factory):
super().__init__()
self.default_factory = default_factory
def __missing__(self, key):
if self.default_factory is None:
raise KeyError(key)
value = self.default_factory()
self[key] = value
return value
dd = DefaultDict(list)
dd['items'].append(1)
dd['items'].append(2)
print(dd['items']) # [1, 2]
__instancecheck__(self, instance) 和 __subclasscheck__(self, subclass)
自定义 isinstance() 和 issubclass() 行为。
class ABCMeta(type):
def __instancecheck__(cls, instance):
print(f"检查 {instance} 是否是 {cls} 的实例")
return type.__instancecheck__(cls, instance)
class MyABC(metaclass=ABCMeta):
pass
class MyClass(MyABC):
pass
obj = MyClass()
isinstance(obj, MyABC) # 会调用 __instancecheck__
__class_getitem__(cls, item)
用于泛型类型提示(Python 3.7+)。
class GenericList:
@classmethod
def __class_getitem__(cls, item):
return f"{cls.__name__}[{item}]"
print(GenericList[int]) # GenericList[int]
print(GenericList[str]) # GenericList[str]
# 用于类型提示
from typing import Generic, TypeVar
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self):
self.items: list[T] = []
def push(self, item: T):
self.items.append(item)
stack: Stack[int] = Stack()
__init_subclass__(cls, **kwargs)
当类被继承时自动调用(Python 3.6+)。
class PluginBase:
plugins = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
print(f"注册插件: {cls.__name__}")
cls.plugins.append(cls)
class Plugin1(PluginBase):
pass
class Plugin2(PluginBase):
pass
print(PluginBase.plugins) # [Plugin1, Plugin2]
__prepare__(metacls, name, bases, **kwargs)
在创建类之前准备命名空间(元类方法)。
from collections import OrderedDict
class OrderedMeta(type):
@classmethod
def __prepare__(metacls, name, bases, **kwargs):
return OrderedDict()
def __new__(cls, name, bases, namespace, **kwargs):
namespace['_order'] = list(namespace.keys())
return super().__new__(cls, name, bases, dict(namespace))
class MyClass(metaclass=OrderedMeta):
z = 1
y = 2
x = 3
print(MyClass._order) # ['__module__', '__qualname__', 'z', 'y', 'x']
__mro_entries__(self, bases)
自定义方法解析顺序(MRO)。
class MyBaseMixin:
def __mro_entries__(self, bases):
print(f"处理 MRO: {bases}")
return (MyMixin,)
class MyMixin:
def greet(self):
return "Hello from MyMixin"
# 使用 MyBaseMixin() 会被替换为 MyMixin
class MyClass(MyBaseMixin()):
pass
obj = MyClass()
print(obj.greet()) # Hello from MyMixin
__await__(self)
使对象可等待(用于异步编程)。
class Awaitable:
def __await__(self):
yield from some_coroutine().__await__()
# 实际例子
import asyncio
class MyFuture:
def __init__(self, value):
self.value = value
def __await__(self):
# 模拟异步操作
future = asyncio.Future()
future.set_result(self.value)
return future.__await__()
async def main():
result = await MyFuture(42)
print(result) # 42
# asyncio.run(main())
__aiter__(self) 和 __anext__(self)
异步迭代器。
class AsyncRange:
def __init__(self, start, end):
self.start = start
self.end = end
def __aiter__(self):
self.current = self.start
return self
async def __anext__(self):
if self.current >= self.end:
raise StopAsyncIteration
await asyncio.sleep(0.1) # 模拟异步操作
self.current += 1
return self.current - 1
async def main():
async for num in AsyncRange(0, 5):
print(num) # 0, 1, 2, 3, 4
# asyncio.run(main())
__aenter__(self) 和 __aexit__(self, exc_type, exc_val, exc_tb)
异步上下文管理器。
class AsyncResource:
async def __aenter__(self):
print("获取资源")
await asyncio.sleep(0.1)
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
print("释放资源")
await asyncio.sleep(0.1)
return False
async def main():
async with AsyncResource() as resource:
print("使用资源")
# asyncio.run(main())
魔法方法速查表
构造与析构
__new__(cls, ...)- 创建实例__init__(self, ...)- 初始化实例__del__(self)- 销毁实例
属性访问
__getattr__(self, name)- 访问不存在的属性__getattribute__(self, name)- 访问任何属性__setattr__(self, name, value)- 设置属性__delattr__(self, name)- 删除属性__dir__(self)- dir() 函数
字符串表示
__str__(self)- str() 和 print()__repr__(self)- repr() 和交互式环境__format__(self, format_spec)- format() 和 f-string__bytes__(self)- bytes()
比较运算
__eq__(self, other)- ==__ne__(self, other)- !=__lt__(self, other)- <__le__(self, other)- <=__gt__(self, other)- >__ge__(self, other)- >=
数值运算
__add__(self, other)- +__sub__(self, other)- -__mul__(self, other)- *__truediv__(self, other)- /__floordiv__(self, other)- //__mod__(self, other)- %__pow__(self, other)- **__matmul__(self, other)- @ (矩阵乘法)
反射运算
__radd__,__rsub__,__rmul__等
增强赋值
__iadd__,__isub__,__imul__等
一元运算
__neg__(self)- -obj__pos__(self)- +obj__abs__(self)- abs()__invert__(self)- ~obj
位运算
__and__(self, other)- &__or__(self, other)- |__xor__(self, other)- ^__lshift__(self, other)- <<__rshift__(self, other)- >>
类型转换
__int__(self)- int()__float__(self)- float()__complex__(self)- complex()__bool__(self)- bool()__index__(self)- 整数索引__round__(self, n)- round()__floor__(self)- math.floor()__ceil__(self)- math.ceil()__trunc__(self)- math.trunc()
容器类型
__len__(self)- len()__getitem__(self, key)- obj[key]__setitem__(self, key, value)- obj[key] = value__delitem__(self, key)- del obj[key]__contains__(self, item)- in__iter__(self)- iter()__reversed__(self)- reversed()
可调用对象
__call__(self, ...)- obj()
上下文管理
__enter__(self)- with 进入__exit__(self, ...)- with 退出
描述符
__get__(self, instance, owner)- 获取属性__set__(self, instance, value)- 设置属性__delete__(self, instance)- 删除属性__set_name__(self, owner, name)- 设置名称
异步编程
__await__(self)- await__aiter__(self)- async for__anext__(self)- async for 下一个__aenter__(self)- async with 进入__aexit__(self, ...)- async with 退出
其他
__hash__(self)- hash()__sizeof__(self)- sys.getsizeof()__copy__(self)- copy.copy()__deepcopy__(self, memo)- copy.deepcopy()__reduce__(self)- pickle__missing__(self, key)- 字典键缺失__instancecheck__(self, instance)- isinstance()__subclasscheck__(self, subclass)- issubclass()__class_getitem__(cls, item)- 泛型类型__init_subclass__(cls, **kwargs)- 继承时调用__prepare__(metacls, name, bases, **kwargs)- 元类命名空间
最佳实践
-
实现
__repr__优于__str____repr__应该返回可重新创建对象的字符串- 如果只定义
__repr__,它也会作为__str__的后备
-
实现比较运算符时使用
@total_ordering- 只需定义
__eq__和一个顺序比较方法 - 装饰器会自动生成其他比较方法
- 只需定义
-
实现
__eq__时也要实现__hash__- 如果两个对象相等,它们的哈希值也应该相等
- 可变对象通常不应该实现
__hash__
-
增强赋值运算符应该返回
self__iadd__等方法必须返回self
-
使用
super()调用父类方法- 在
__new__,__init__,__getattribute__等方法中
- 在
-
避免在
__getattribute__中使用self.attr- 会导致无限递归
- 使用
super().__getattribute__(name)
-
上下文管理器的
__exit__返回值很重要- 返回
True抑制异常 - 返回
False或None让异常继续传播
- 返回
-
描述符应该使用弱引用或
id(instance)存储数据- 避免内存泄漏
总结
Python 的魔法方法提供了强大的机制来自定义类的行为,使得自定义对象能够像内置类型一样使用。掌握这些魔法方法可以:
- 让代码更加 Pythonic
- 使自定义类与 Python 内置函数和运算符无缝集成
- 实现更加优雅和直观的 API
- 提供更好的用户体验
关键是要理解每个魔法方法的调用时机和用途,并在适当的场景下使用它们。不要过度使用 - 只在能够提升代码可读性和易用性时才实现这些方法。