Python 中的特殊方法主要是为了被解释器调用的,因此应该尽量使用 len(my_object)
而不是 my_object.__len__()
这种写法。在执行 len(my_object)
时,Python 解释器会自行调用 my_object 中实现的 __len__
方法。
除非有大量的元编程存在,直接调用特殊方法的频率应远小于实现它们的次数。
模拟数值类型
可以通过在自定义对象中实现 __add__
和 __mul__
等特殊方法 ,令其支持 +
、*
等运算符。
如下面的模拟向量的 Vector 类:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# vector.py
from math import hypot
class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __repr__(self):
return f'Vector({self.x}, {self.y})'
def __abs__(self):
return hypot(self.x, self.y)
def __bool__(self):
return bool(self.x or self.y)
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
运行效果如下:1
2
3
4
5
6
7
8
9
10from vector import Vector
2, 4) v1 = Vector(
2, 1) v2 = Vector(
v1 + v2
Vector(4, 5)
3, 4) v = Vector(
abs(v)
5.0
3 v *
Vector(9, 12)
对象的字符串表示
Python 有一个 repr
内置函数,能把一个对象用字符串的形式表示出来。实际上这种字符串表达是通过对象内部的 __repr__
特殊方法定义的。默认情况下,在控制台里查看某个对象时,输出的字符串一般是 <xxx object at 0x7fc99d6ab2e0>
这种形式。
__repr__
返回的字符串应该准确、无歧义,并尽可能表示出该对象是如何创建的。比如前面的 Vector 对象,其 __repr__
中定义的字符串形式类似于 Vector(3, 4)
,和对象初始化的语法非常近似。
__repr__
和 __str__
的区别在于,__str__
是在向对象应用 str()
函数(或者用 print
函数打印某个对象)时被调用。其返回的字符串对终端用户更友好。
如果只想实现其中一个特殊方法,__repr__
应该是更优的选择。在对象没有实现 __str__
方法的情况下,Python 解释器会用 __repr__
代替。
1 | # myclass.py |
1 | from myclass import MyClass |
自定义布尔值
Python 里有 bool 类型,但实际上任何对象都可以用在需要 bool 类型的上下文(比如 if
或 while
语句)中。为了判断某个值 x 的真假,Python 会调用 bool(x)
返回 True 或 False。
默认情况下,自定义类的实例总是为真。除非这个类对于 __bool__
或 __len__
方法有自己的实现。bool(x)
实际上调用了对象 x 中的 __bool__
方法。如不存在 __bool__
方法,则 bool(x)
会尝试调用 x.__len__()
,返回 0 则为 False,否则为 True。
1 | # boolclass.py |
1 | from boolclass import BoolClass |
1 | # boolclass.py |
1 | from boolclass import BoolClass |