基础的魔法方法在下面这篇文章有介绍。
基础魔法方法https://blog.csdn.net/qq_49873907/article/details/130230106?spm=1001.2014.3001.5501
这篇文章主要介绍一下Python与运算相关的魔法方法会挑选择几个经典的方法来详细说明。
一、与运算相关的魔法方法
1.1 算术运算
与算数运算有关的魔法方法如下表:
魔法方法 | 行为 |
---|---|
__add__(self, other) | 定义加法的行为 : + |
__sub__(self, other) | 定义减法的行为 : - |
__mul__(self, other) | 定义乘法的行为:* |
__truediv__(self, other) | 定义真除法的行为 : / |
__floordiv__(self, other) | 定义整数除法的行为 : // |
__mod__(self, other) | 定义取模算法的行为:% |
__divmod__(self, other) | 定义当被 divmod0 调用时的行为 |
__pow__(self, otherl modulo]) | 定义当被 power0 调用或 ** 运算时的行为 |
__Ishift__(self, other) | 定义按位左移位的行为 :<< |
__rshift__(self, other) | 定义按位右移位的行为 :>> |
__and__(self,other) | 定义按位与操作的行为 :& |
__xor__(self, other) | 定义按位异或操作的行为 :^ |
__or__(self, other) | 定义按位或操作的行为 :| |
1.1.1 __add__(self, other)
对于上述表格中的一些算数相关的魔法方法,使用的方式都是一样的,我们选择__add__(self, other)来进行简单的介绍。
对于这些方法我们可以改变原有的功能,自定义魔法方法,举个例子:比如__add__(self, other)是用来拼接两个字符串,我们可以对其进行修改,用自己的方法去覆盖Python中默认的方法,当触发加法操作的时候,进行字符串长度的求和。
class A(str): #继承str类,str类中有多种关于字符串的操作函数
def __add__(self,other): #重写__add__()方法
return len(self)+len(other) #定义方法功能为计算字符串的长度
a1 = A("hello") #创建实例对象a1
a2 = A("world") #创建实例对象a2
a1+a2 #输出a1+a2的结果
# 10
这里我们得到了 ‘hello’ + ‘world’ 字符串的长度——10,而不是拼接后的字符串‘helloworld’,因为我们对其进行了拦截,检测到加法操作的时候去执行了我们定义的功能。
我们知道,对于加法操作要有两个对象才行,那么我们重写的__add__()方法是属于‘+’前面的对象还是后面的对象呢?我们来简单测试一下:
class A(str):
def __add__(self,other):
return len(self)+len(other)
a1 = A("hello")
a2 = A("world")
a1+"world"
# 10
"hello" +a2
# 'helloworld'
通过结果我们可以看出,重写的__add__()方法是属于‘+’前面的对象,其实这样的写法就相当于a1[self].__add__(a2[other])。对于其他与算数运算相关的魔法方法也是类似的用法,这里不再一一举例。
1.2 反算数运算
与反算数运算有关的魔法方法如下表:
魔法方法 | 行为 |
---|---|
__radd__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rsub__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rmul__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rtruediv__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rfloordiv__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rmod__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rdivmod__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rpow__(self, otherl modulo]) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rIshift__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__vrshift__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__rxor__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
__ror__(self, other) | ( 与算数运算相同,当左操作数不支持相应的操作时被调用) |
对于反算数运算方法的调用前提是:对两个对象进行相关运算(比如加法运算),如果左侧的对象和右侧的对象是不同类型(不同类的对象),并且左侧的对象没有定义__add__()方法,或者是其__add__()方法返回 NotImplemented(没有实现)那么Python就会去右侧的对象中查找是否有__radd__()方法的定义。
1.2.1 __radd__(self, other)
根据上述描述,我们定义一个加法操作来验证:
class A(str):
def __add__(self,other):
return NotImplemented #返回NotImplemented 表示没有实现的功能
class B(str):
def __radd__(self,other): #定义__radd__(self,other)
return len(self)+len(other)
a = A("hello")
b = B("world")
a+b
# 10
我们明明没有实现__add__()的功能,可是结果还是得到了字符串的长度,说明我们的__radd__() 方法起到了作用。
这里一定要注意的两点是:
①左侧和右侧的对象是不同类型
②左侧没有实现相应的魔法方法
比如我们使用相同类型的对象进行运算:
class B(str):
def __radd__(self,other):
return len(self)+len(other)
b1 = B("haha")
b2 = B("yeye")
b1+b2
# 'hahayeye'
由于b1和b2属于同一个类的对象,所以不会去使用__radd__()的方法,而会去调用父类中的字符串拼接方法。
1.3 增强赋值运算
与增强赋值运算有关的魔法方法如下:
魔法方法 | 行为 |
---|---|
__iadd__(self, other) | 定义赋值加法的行为 : + = |
__isub__(self, other) | 定义赋值减法的行为 : - = |
__imul__(self, other) | 定义赋值乘法的行为:* = |
__itruediv__(self, other) | 定义赋值真除法的行为 : / = |
__ifloordiv__(self, other) | 定义赋值整数除法的行为 : // = |
__imod__(self, other) | 定义赋值取模算法的行为:% = |
__ipow__(self, otherl modulo]) | 定义赋值幂运算时的行为:** = |
__iIshift__(self, other) | 定义赋值按位左移位的行为 :<< = |
__irshift__(self, other) | 定义赋值按位右移位的行为 :>> = |
__iand__(self,other) | 定义赋值按位与操作的行为 :& = |
__ixor__(self, other) | 定义赋值按位异或操作的行为 :^ = |
__ior__(self, other) | 定义赋值按位或操作的行为 :| = |
所谓增强赋值运算,就是运算兼赋值的操作,也就是说s1+=s2相当于s1=s1.__iadd__(s2),
参数是s2这么个意思。增强运算会修改对象自身进行自我赋值。
1.3.1 __iadd__(self, other)
class S1(str):
def __iadd__(self,other):
return len(self)+len(other)
class S2(str):
def __radd__(self,other):
return len(self)+len(other)
s1 = S1("python")
s2 = S2("java")
s1 += s2 #出发赋值运算
s1
# 10
对于增强赋值运算,如果运算符左边没有实现__iadd__(self, other)方法,那么python会去寻找__radd__(self, other)和__add__(self, other)方法。例如:
class S2(str):
def __radd__(self,other):
return len(self)+len(other)
ss = S2("111")
sss= S2("222")
ss += sss
ss
#'111222'
上述代码中没有实现__iadd__(self, other)方法,但是也没有执行__radd__(self, other)的方法,这是为什么呢?因为我们创建的实例对象ss和sss属于同一个对象,而__radd__(self, other)触发的条件时来自不同类的对象,所以不会打印出字符串的长度。