引言
魔术方法(Magic Methods)是Python对象模型的核心。理解它们,能写出与内置类型一样自然优雅的类。本文系统讲解常用魔术方法及实战。
一、对象生命周期
python
复制
下载
class Resource: def __new__(cls, *args, **kwargs): print("__new__") return super().__new__(cls) def __init__(self, name): print("__init__") self.name = name def __del__(self): print("__del__") r = Resource("test") # __new__ → __init__ del r # __del__newvsinit
__new__:创建实例,返回实例__init__:初始化实例
单例、不可变类型常用__new__。
二、字符串表示
python
复制
下载
class User: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return f"{self.name}({self.age})" def __repr__(self): return f"User(name={self.name!r}, age={self.age})" u = User("Tom", 20) print(str(u)) # Tom(20) print(repr(u)) # User(name='Tom', age=20) # 容器中打印用repr print([u]) # [User(name='Tom', age=20)]规则:__repr__面向开发者,__str__面向用户。若只实现一个,用__repr__。
三、比较与哈希
python
复制
下载
class Point: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): if not isinstance(other, Point): return NotImplemented return self.x == other.x and self.y == other.y def __hash__(self): return hash((self.x, self.y)) def __lt__(self, other): return (self.x, self.y) < (other.x, other.y)
规则:
定义
__eq__必须定义__hash__(否则不可哈希)返回
NotImplemented而非False,让Python尝试反向比较
四、算术运算
python
复制
下载
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 __rmul__(self, scalar): return self.__mul__(scalar) def __neg__(self): return Vector(-self.x, -self.y) def __abs__(self): return (self.x ** 2 + self.y ** 2) ** 0.5 v = Vector(1, 2) + Vector(3, 4) print(abs(v))
五、容器协议
5.1 序列
python
复制
下载
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 __iter__(self): return iter(self._data) def __contains__(self, item): return item in self._data def __reversed__(self): return reversed(self._data)
5.2 字典
python
复制
下载
class Config: def __init__(self): self._data = {} def __getitem__(self, key): return self._data[key] def __setitem__(self, key, value): self._data[key] = value def __delitem__(self, key): del self._data[key] def __contains__(self, key): return key in self._data def __missing__(self, key): return None六、属性访问
6.1getattrvsgetattribute
python
复制
下载
class Dynamic: def __getattr__(self, name): # 仅属性不存在时调用 return f"动态属性: {name}" def __getattribute__(self, name): # 所有属性访问都调用,慎用 return super().__getattribute__(name) def __setattr__(self, name, value): # 所有赋值都调用 super().__setattr__(name, value) def __delattr__(self, name): super().__delattr__(name)6.2 __getattr__实战
python
复制
下载
class ApiClient: def __init__(self, base_url): self.base_url = base_url def __getattr__(self, name): if name.startswith("get_"): resource = name[4:] def method(**params): return self._request("GET", f"/{resource}", params) return method raise AttributeError(name) def _request(self, method, path, params): # ... pass client = ApiClient("https://api.example.com") client.get_users(limit=10)七、上下文管理器
python
复制
下载
class Timer: def __enter__(self): self.start = time.perf_counter() return self def __exit__(self, exc_type, exc_val, exc_tb): self.cost = time.perf_counter() - self.start print(f"耗时: {self.cost:.4f}s") return False # 不吞异常 with Timer(): time.sleep(1)八、可调用对象
python
复制
下载
class Multiplier: def __init__(self, factor): self.factor = factor def __call__(self, x): return x * self.factor double = Multiplier(2) print(double(5)) # 10 print(callable(double)) # True
九、迭代器与生成器协议
python
复制
下载
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 n in Countdown(3): print(n)
十、其他常用魔术方法
python
复制
下载
class MyClass: def __bool__(self): return True def __format__(self, format_spec): return f"formatted:{format_spec}" def __enter__(self): ... def __exit__(self, *args): ... def __copy__(self): ... def __deepcopy__(self, memo): ... def __getstate__(self): ... def __setstate__(self, state): ... def __slots__ = ()十一、实战:ORM模型
python
复制
下载
class Field: def __init__(self, name): self.name = name def __set_name__(self, owner, name): self.attr = name def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get(self.attr) def __set__(self, obj, value): obj.__dict__[self.attr] = value class Model: def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) def __repr__(self): fields = ", ".join(f"{k}={v!r}" for k, v in self.__dict__.items()) return f"{type(self).__name__}({fields})" def __eq__(self, other): return type(self) == type(other) and self.__dict__ == other.__dict__ class User(Model): name = Field("name") age = Field("age") u = User(name="Tom", age=20) print(u) print(u == User(name="Tom", age=20))十二、总结
魔术方法让自定义类像内置类型一样自然。核心:__repr__、__eq__、__hash__、容器协议、上下文管理器、__call__。避免滥用__getattribute__和__del__,前者影响性能,后者时机不确定。