python类的运算符重载意味着在类方法中拦截内置的操作,当类的实例出现在内置操作中,python自动调用你重载的方法。常见的运算符重载方法如下(运算符的重载都是在类中进行定义的):

__init__,__del__,__new__

方法:__init__ 重载了:构造函数 ;程序中的调用方式: X = Class(args)对象建立

方法:__del__ 重载了:析构函数 ;程序中的调用方式: del var 删除对象引用,当对象的引用变为0时会自动调用__del__方法。一般来说python的对象回收机制的析构函数很少使用(因为无法确定会何时调用__del__函数)

方法:__new__ 重载了:申请内存空间 ;程序中的调用方式: 在init前在内存中创建内存空间,是一个静态函数

__add__,__radd__,__iadd__

方法:__add__ 重载了:运算符+ ;程序中的调用方式:如果没有__iadd__ ,X+Y, X+=Y

方法:__iadd__ 重载了:实地加法 ;程序中的调用方式:X+=Y

方法:__radd__ 重载了:右侧加法;程序中的调用方式:Other+X,只有当+右侧对象是类实例,左侧对象不是类实例时,python才会调用__radd__,(__radd__一般用来支持可互换的运算符)

当不同类的实例混合出现在表达式时,python优先选择左侧的那个类

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

34class (object):

def __init__(self, value):

self.value = value

def __add__(self, other):

print('add', self.value, other)

return self.value + other

def __radd__(self, other):

print('radd', self.value, other)

return other + self.value

x = MyObject(88)

print(x+2) # x传入self中,2 传入other中

"""

输出结果:

add 88 2

90

"""

y = MyObject(99)

print(1+y) # y传入self中,other传入1 ,调用__radd__

"""

输出结果:

radd 99 1

100

"""

print(x + y) # x+y 调用__add__,__add__再调用__radd__

"""

输出结果:

add 88 <__main__.myobject object at>

radd 99 88

187

"""

上例中,如果不定义__radd__运行x+y会报错,如果不想报错,可以使用下面办法

1

2

3

4

5

6

7

8

9

10

11

12

13

14class (object):

def __init__(self, value):

self.value = value

def __add__(self, other):

if isinstance(other, MyObject):

other = other.value

return self.value + other

x = MyObject(88)

y = MyObject(99)

print(x + y) # x+y 直接调用__add__ 187

__or__,__ior__

方法:__or__ 重载了:运算符| ;程序中的调用方式:如果没有__ior__ ,X|Y, X|=Y

__repr__,__str__

方法:__repr__、__str__ 重载了:打印转换;程序中的调用方式:print(X),repr(X),str(X),返回字符串表达形式

打印会首先尝试__str__,交互模式下会首先尝试__repr__

__index__

方法:__index__ 重载了:整数值;程序中的调用方式:hex[X]、bin(X)、oct(X),返回一个整数值

__call__

方法:__call__ 重载了:函数调用;程序中的调用方式:X(*args , **kwargs)

__getattr__,__setattr__,__delattr__,__getattribute__,__get__,__set__

方法:__getattr__ 重载了:点号运算;程序中的调用方式:X.undefined。即当通过对未定义的属性名称和实例进行点好运算时,就会用属性名称作为字符串调用这个方法。如果python可以通过其继承树搜索流程找到这个属性,该方法不会被调用

方法:__setattr__ 重载了:属性赋值语句;程序中的调用方式:X.any = value,使用X.any = value相当于调用self.__setattr__('attr',value),因此在__setattr__ 中对任何self属性做赋值都会在调用__setattr__ ,导致无穷递归循环,如果要使用这个方法,要通过对属性字典做索引运算来进行赋值来避免无穷循环

方法:__delattr__ 重载了:属性删除;程序中的调用方式:del X.any

方法:__getattribute__ 重载了:属性获取;程序中的调用方式:X.any(getattr(X,attr)公共函数默认调用这个方法)

方法:__get__,__set__ 重载了:描述符属性;程序中的调用方式:X.attr,X.attr = value, del X.attr

1

2

3

4

5

6

7

8

9

10

11

12

13class (object):

def __setattr__(self, attr, value):

if attr == 'age':

self.__dict__[attr] = value # 不可以使用self.attr = value避免循环调用

else:

raise AttributeError(attr + ' not allowed')

X = MyObject()

X.age = 40

print(X.age) # 40

X.name = 'mel' # 出错 AttributeError: name not allowed

__getitem__,__setitem__,__delitem__

方法:__getitem__ 重载了:索引运算;程序中的调用方式:X[key],X[i:j],没有__iter__时的for循环和其他迭代器

方法:__setitem__ 重载了:索引赋值语句;程序中的调用方式:X[key]=value,X[i:j]=sequence

方法:__delitem__ 重载了:索引和切片删除;程序中的调用方式:del X[key],del X[i:j]

1

2

3

4

5

6class (Object):

def __getitem__(self,index):

pass

return something

def __setitem__(self,index,value)

pass # set something

__iter__,__next__

重载了:迭代环境;程序中的调用方式:I = iter(X),next(I),map(F,X)等其他迭代情况

python的所有迭代环境中都会优先尝试__iter__方法,没有__iter__才会尝试__getitem__方法

1

2

3

4

5

6

7class (object):

def __iter__(self):

pass

return self # return self只支持单一迭代器

def __next__(self)

if test :raise StopIteration # 如果超过边界则产生异常

return something

__len__,__bool__

方法:__len__ 重载了:长度;程序中的调用方式:len(X),如果没有__bool__的真值测试,则尝试通过__len__来获取真值信息

方法:__bool__ 重载了:布尔测试;程序中的调用方式:bool(X)

__lt__,__gt__,__le__,__ge__,__eq__,__ne__

重载了:特定的比较;程序中的调用方式:XY,X<=Y,X>=Y,X==Y,X!=Y返回布尔值

注意:__eq__,__ne__必须都定义

__contains__

重载了:成员关系测试;程序中调用方式:item in X(任何可迭代的)

1

2

3

4class MyObject(object):

def __contains__(self,x): # 用于判断元素是否在x是否在self中

pass

return 布尔值

__enter__,__exit__

重载了:环境管理器;程序中的调用方式:with obj as var: