一、str — 用户友好的字符串表示
触发时机
- 调用 str(obj) 时
- 使用 print(obj) 时
- 使用 f”{obj}” 或 “{}”.format(obj) 时
用途
给普通用户看的可读字符串,注重可读性
1 2 3 4 5 6 7 8 9 10 11 12
| class Person: def __init__(self, name, age): self.name = name self.age = age
def __str__(self): return f"姓名: {self.name}, 年龄: {self.age}"
p = Person("张三", 25) print(p) print(str(p)) print(f"{p}")
|
二、repr — 开发者调试用的字符串表示
触发时机
- 在交互式解释器中直接输入对象时
- 调用 repr(obj) 时
- 未定义 str 时,print() 会回退使用 repr
- f”{obj!r}” 时
用途
给开发者看的字符串,注重准确性,理想情况下可以用来重建对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Person: def __init__(self, name, age): self.name = name self.age = age
def __repr__(self): return f"Person(name={self.name!r}, age={self.age!r})"
def __str__(self): return f"姓名: {self.name}, 年龄: {self.age}"
p = Person("张三", 25) repr(p) print(p)
print([p])
|
三、len — 定义对象长度
触发时机
- 调用 len(obj) 时
- 用于布尔判断时(len == 0 则为 False)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Playlist: def __init__(self): self.songs = []
def add(self, song): self.songs.append(song)
def __len__(self): return len(self.songs)
pl = Playlist() pl.add("歌曲A") pl.add("歌曲B")
print(len(pl))
if pl: print("播放列表不为空")
empty_pl = Playlist() if not empty_pl: print("播放列表为空")
|
四、eq — 定义相等性判断
触发时机
默认行为
未定义时,== 比较的是内存地址(同 is)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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
p1 = Point(1, 2) p2 = Point(1, 2) p3 = Point(3, 4)
print(p1 == p2) print(p1 == p3) print(p1 == "abc")
|
五、其他常用魔术方法速览
比较运算符系列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Temperature: def __init__(self, celsius): self.celsius = celsius
def __eq__(self, other): return self.celsius == other.celsius def __ne__(self, other): return self.celsius != other.celsius def __lt__(self, other): return self.celsius < other.celsius def __le__(self, other): return self.celsius <= other.celsius def __gt__(self, other): return self.celsius > other.celsius def __ge__(self, other): return self.celsius >= other.celsius
t1 = Temperature(20) t2 = Temperature(30) print(t1 < t2) print(t1 > t2)
|
技巧:使用 @functools.total_ordering 只需实现 eq 和一个比较方法,其余自动推导。
1 2 3 4 5 6 7 8 9 10 11 12 13
| from functools import total_ordering
@total_ordering class Temperature: def __init__(self, celsius): self.celsius = celsius
def __eq__(self, other): return self.celsius == other.celsius
def __lt__(self, other): return self.celsius < other.celsius
|
算术运算符系列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 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 __repr__(self): return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) print(v1 * 3) print(3 * v1) print(-v1)
|
容器协议系列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class MyList: def __init__(self): self._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 __contains__(self, item): return item in self._data
def __iter__(self): return iter(self._data)
|
生命周期与上下文管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class DatabaseConnection: def __init__(self, url): self.url = url self.conn = None
def __enter__(self): self.conn = connect(self.url) return self.conn
def __exit__(self, exc_type, exc_val, exc_tb): self.conn.close() return False
def __del__(self): if self.conn: self.conn.close()
with DatabaseConnection("db://localhost") as conn: conn.query("SELECT * FROM users")
|
hash — 配合 eq 使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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)
d = {p1: "point A"} print(d[p2])
s = {p1, p2} print(len(s))
|
六、魔术方法总览表
| 类别 |
方法 |
触发场景 |
| 字符串 |
str |
print(), str(), f”{}” |
| 字符串 |
repr |
repr(), 交互器, 容器中 |
| 长度 |
len |
len(), 布尔判断 |
| 比较 |
eq lt gt |
== < > |
|
|
|
|
|
|
|
|
|
核心原则:魔术方法让自定义类与Python内置语法深度集成,是Python鸭子类型思想的核心体现——只要实现了对应的魔术方法,对象就能支持对应的语法和操作。