一 . 模拟数值类型
示例1
from math import hypot
class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __repr__(self): #定义输出表示方法
return 'Vector(%r, %r)' % (self.x, self.y)
def __abs__(self):
return hypot(self.x, self.y) #求向量的模
def __bool__(self):
return bool(abs(self))
def __add__(self, other): #定义+方法
x = self.x + other.x
y = self.y + other.y
return Vector(x, y)
def __mul__(self, other): #定义 * 方法
return Vector(self.x * other, self.y * other)
v1 = Vector(2,4)
v2 = Vector(2,1)
print(v1 + v2)
v = Vector(3, 4)
print(abs(v))
print(abs(v * 3))
二. 字符串表示形式
python有一个内置的函数叫做repr,他能把一个对象用字符串的形式表达出来以便辨认,这个就是"字符串表示形式"。repr就是通过_repr_这个特殊方法来得到一个对象的字符串表示形式的。如果没有实现_repr_,当我们在控制台中打印一个向量的实例时,得到的字符串可能会是<Vectr object at 0x10e888>
交互式控制台和调试程序(debugger)用repr函数来获取字符串表示形式,在老的使用%符号的字符串格式中,这个函数返回的结果用来代替%r(2)所代表的对象;同样,str.format()(2)函数所用到的新式字符串格式化语法,也是利用了repr,才把!r字段变成字符串。
1. str.formar()
print('我叫{},今年{}岁。'.format('小明', 18))
"""
我叫小明,今年18岁。
"""
2. %
print('我叫%s,今年%s岁。'%('小明', 18))
"""
我叫小明,今年18岁。
"""
在_repr_的实现中,我们用到了%r来获取对象各个属性的标准字符串表示形式,这是个好习惯,它暗示了一个关键:verctor(1,2)和verctor(“1”,“2”)是不一样的,后者在我们定义中会报错,因为向量对象的构造函数只接受数值,不接受字符串。
在_repr_所返回的字符串应该准确,无歧义,并且尽可能表达出如何使用代码创建出的这个被打印的对象。因此这里使用了类似调用对象构造器的表达形式,(比如Vector(3,4)就是这个例子)。
在_repr_和_str_的区别在于,后者是在str()函数被使用,或是在用print函数打印一个对象的时候才被调用的,并且它返回的字符串对终端用户更加友好。
如果你只想实现这两个特殊方法中的一个,这个_repr_是更好的选择,因为如果一个对象没有_str_函数。而python又需要调用它的时候,解释器会用_repr_作为代替
三. 算数运算符
通过_add_和_mul_,示例1为向量类带来了+和*这两个算术运算符。值得注意的是,这两个方法的返回值,都是新建的向量对象,被操作的两个向量(self或者other)还是原封不动,代码里只是读取了他们的值而已,中缀运算符的基本原则就是不改变对象,而是产出一个新的值。
四. 自定义布尔值
尽管python里有bool类型,但实际上任何对象都可以用于需要布尔值的上下文中(比如if或者while语句,或者and,or,not运算符)。为了判定一个值X为真还是为假,Python会调用bool(x),这个函数只能返回True或者False
默认情况下,我们自己定义的类的实例总被认为是真的,除非这个类对_bool_或者_len_函数有自己的实现。bool(x)的背后是调用x.bool()的结果,如果不存在_bool_方法,那么bool(x)会尝试调用x.len().若返回0,则bool会返回False,否则返回True
我们对__bool__的实现很简单,如果一个向量的模是0,那么就返回False,其他情况则返回True。因为__bool__函数的返回值类型应该是bool型,所以我们通过bool(abs(self))把模值换成了布尔值。
在python标准库中,有一节叫做“Built-in Types”,其中规定了真值检验的标准。通过实现_bool_,你定义的对象就可以与这个标准保持一致。