什么是 dunder
双下划线(double underscore)方法——__xxx__。Python 用它们让你的类能用 +、==、len()、for 等内置语法。
str vs repr
class Player:
def __init__(self, name, hp):
self.name = name
self.hp = hp
def __str__(self): # 给人看的(print 用)
return f"{self.name}(HP={self.hp})"
def __repr__(self): # 给开发者看的(控制台 / log 用)
return f"Player(name={self.name!r}, hp={self.hp})"
p = Player("WadeLy", 100)
print(p) # WadeLy(HP=100)
print(repr(p)) # Player(name='WadeLy', hp=100)
[p, p] # [Player(name='WadeLy', hp=100), ...] list 用 repr
只写一个的话写 __repr__——str 不存在时会回退到它。
eq + hash
让对象可以用 == 比较,也能放进 set / dict 当 key:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return isinstance(other, Point) and (self.x, self.y) == (other.x, other.y)
def __hash__(self):
return hash((self.x, self.y))
Point(1, 2) == Point(1, 2) # True
{Point(1, 2), Point(1, 2)} # 集合里只有一个
⚠️ 重写 __eq__ 必须重写 __hash__,否则对象会变成不可哈希的。
len + getitem:让对象长得像列表
class Deck:
def __init__(self):
self.cards = ["A", "2", "3", "...K"]
def __len__(self):
return len(self.cards)
def __getitem__(self, idx):
return self.cards[idx]
d = Deck()
len(d) # 4
d[0] # 'A'
d[1:3] # 切片也能用!(前提是底层 list 支持)
for c in d: # for 也能用!(有 __getitem__ 就够)
print(c)
iter + next
讲过了——让对象成为迭代器。
call:让对象像函数
class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return x + self.n
add5 = Adder(5)
add5(10) # 15 像调函数一样调它
类装饰器、缓存器、配置器常用这个。
enter + exit
讲过了——让对象支持 with。
数学运算符:add / sub / ...
class Vec:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vec(self.x + other.x, self.y + other.y)
def __mul__(self, k):
return Vec(self.x * k, self.y * k)
def __repr__(self):
return f"Vec({self.x}, {self.y})"
a = Vec(1, 2)
b = Vec(3, 4)
print(a + b) # Vec(4, 6)
print(a * 3) # Vec(3, 6)
| 符号 | 方法 |
|---|---|
+ |
__add__ |
- |
__sub__ |
* |
__mul__ |
/ |
__truediv__ |
// |
__floordiv__ |
% |
__mod__ |
** |
__pow__ |
< |
__lt__ |
> |
__gt__ |
== |
__eq__ |
全部魔术方法的速查
dir(int) / dir(list) 看内置类型实现了哪些 dunder——直接抄它们的方法名。
别滥用
写"Vec + Vec" 让代码更清晰——好。
写 "User > User" 比较年龄——别。读代码的人猜不到 > 的语义。
下一篇讲 property 与描述符——getter/setter 的优雅写法。