社区专栏>python中一些特殊方法的自定义及作用>
引言
1 2 3
|
聊一聊__add__,__mul__,__len__,__bool__的作用和自定义,以及__len__和 __bool__是怎么影响if/while的条件判断,另外说一说怎么把一个对象以字符串的 形式表现。
|
自定义运算符
使用场景
1 2
|
自定义一个类, 类中有两个属性分别为x和y, 实现a+b a*b的功能,要求a+b实现a.x+b.x a.y+b.y; a*b实现a.x*b.x a.y*b.y
|
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
class V(object):
def __init__(self, x, y): self.x = x self.y = y
def __add__(self, v): print('run __add__') return V(x=v.x + self.x, y=v.y + self.y)
def __mul__(self, v): print('run __mul__') return V(x=v.x * self.x, y=v.y * self.y)
v = V(1, 2) print('---------------add----------') new_v = v + v print(new_v.x)
print('---------------mul----------') new_v = v * v print(new_v.y)
|
自定义bool值
关于if v
1 2 3
|
默认情况下我们自己定义的类的实例总是被认为时真的,但是有的时候这个默认值不是我们想要的, 除非我们自己定义__bool__或者__len__才能实现我们想要的结果,我们还以刚才的类V举例, 我想你总不希望当x和y都是0的时候还希望if v成立吧
|
关于bool()
1 2 3
|
像if v/if not v等,python会调用bool(v)方法,而bool(v)背后的调用时尝试调用 v.__bool__(),如果没有__bool__方法,就会尝试调用__len__方法,若这是返回0则 是False否则为True,这两个方法都没有的话只能按照默认处理了
|
实现
bool和len都没有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
class V(object):
def __init__(self, x, y): self.x = x self.y = y
v = V(1, 2)
print('--------------if----------') if v: print('\tif True') else: print('\tif False')
print('-------------while----------') while v: print('\twhile True') break 执行结果: --------------if---------- if True -------------while---------- while True
|
只有len
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 30
|
class V(object):
def __init__(self, x, y): self.x = x self.y = y
def __len__(self): print('run __len__') return self.x + self.y
v = V(1, 2)
print('--------------if----------') if v: print('\tif True') else: print('\tif False')
print('-------------while----------') while v: print('\twhile True') break
执行结果: --------------if---------- run __len__ if True -------------while---------- run __len__ while True
|
bool与len都有
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 30 31 32 33 34 35
|
class V(object):
def __init__(self, x, y): self.x = x self.y = y
def __bool__(self): print('run __bool__') return bool(self.x or self.y)
def __len__(self): print('run __len__') return self.x + self.y
v = V(1, 2)
print('--------------if----------') if v: print('\tif True') else: print('\tif False')
print('-------------while----------') while v: print('\twhile True') break
执行结果: --------------if---------- run __bool__ if True -------------while---------- run __bool__ while True
|
如何使对象以字符串的形式表现
为什么要以字符串的形式
1 2 3
|
我们把一个对象以字符串的形式表现出来,是为了更好的辨认,方便后续处理或让用户觉得更加直观, 最普遍的是在django的admin中,我们希望看到一行数据的谁的数据,而不是希望看到一个class 或其他无法辨识的表现形式。
|
只用str实现
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
|
class Student(object):
def __init__(self, name): self.name = name
def __str__(self): print('\t-------------call __str__-------------\n') return self.name
s = Student('baisong') print('------ s is:', s)
print('---str--- s is:', str(s))
print('---repr---s is:', repr(s))
执行结果: ------ s is: -------------call __str__-------------
baisong
-------------call __str__-------------
---str--- s is: baisong
---repr---s is: <__main__.Student object at 0x7f64d6fedd30>
|
只用repr实现
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 30 31 32 33 34
|
class Student(object):
def __init__(self, name): self.name = name
def __repr__(self): print('\tcall __repr__') print('\t-------------call __str__-------------\n') return self.name
s = Student('baisong') print('------ s is:', s)
print('---str--- s is:', str(s))
print('---repr---s is:', repr(s))
执行结果: ------ s is: call __repr__ -------------call __str__------------- baisong
call __repr__ -------------call __str__------------- ---str--- s is: baisong
call __repr__ -------------call __str__------------- ---repr---s is: baisong
|
repr与str的不同
1 2 3 4 5
|
从上边例子可以看出来__repr__与__str__的区别在于,后者实在str()被使用, 或者在 print的时候调用, __str__返回的字符串对于终端用户更友好。而__repr__是由python 的内置函数repr调用, 如果说你只想用其中的一个,建议使用__repr__, 因为python解释 器会在没有__str__的时候用__repr__代替(前边的例子print已经展示出来), 读者可以自 己试试当__repr__与__str__都存在的输出结果。
|