python运算符重载
1. 重载的概念
重载一般指函数重载。是在一个类里面,函数名字相同,而参数不同。由于python参数没有类型,所以在python中,是没有函数重载的。比如下面这样运行后直接报错。写多个同名的函数,只有最后一个生效。
2. 运算符重载
运算符重载指的是将运算符与类方法关联起来,每个运算符对应一个指定的内置方法。python通过重写这些内置的方法,实现运算符的重载功能。
3. __str__重载
当我们调用print()函数打印对象时,其实是调用了对象的__str__()函数。
class Vector(object): def __init__(self, x=None, y=None): self.x=x self.y=y def __str__(self): return f"Vector{self.x,self.y}" v1=Vector(1,1) print(v1)
4. 加法运算重载
加法重载为__add__函数或__iadd__函数,两者有区别。对于不可变对象,比如int变量,元组等,只有__add__函数可以重载。没有__iadd__函数。对于可变对象,如类对象,列表等有__add__函数与__iadd__函数。__add__返回新对象,__iadd__返回旧对象。对于可变对象什么时候调用__add__,又什么时候调用__iadd__看下面例子。
class Vector(object): def __init__(self, x=None, y=None): self.x=x self.y=y #返回新对象 def __add__(self, other): print("调用了_add__") #函数可以根据传入的参数类型,决定行为 if type(other)==Vector: x=self.x+other.x y=self.y+other.y else: x=self.x+other y=self.y+other return Vector(x,y) #返回旧对象 def __iadd__(self, other): print("调用了__iadd__") self.x+=other.x self.y+=other.y return self def __str__(self): return f"Vector{self.x,self.y}" v1=Vector(1,1) v2=Vector(1,2) v3=v1+v2 print(v3) v4=Vector(0,0) print("v4的id=",id(v4)) v4+=Vector(0,1) print("v4的id=",id(v4)) print(v4) v5=Vector(1,0) print("v5的id=",id(v5)) v5=v5+Vector(2,2) print("v5的id=",id(v5)) print(v5)
可以发现使用v4+=Vector(0,1)后v4对象的内存地址没有发生变化,因为调用的是__iadd__。而v5=v5+Vector(2,2)内存地址发生了变化,因为调用了__add__,生成了一个新的对象。再看下面的例子:
""" 对象池 一种内存优化机制 python3.1开始:不可变数据,具有对象池 """ #可变对象包括列表、字典等 list01=[10] print(id(list01))#1698365395464 list01+=[20]#注意与下面list02=list02+[]的区别 print(id(list01))#1698365395464 list02=[10] print(id(list02))#1698365395976 list02=list02+[20] print(id(list02))#1698366665544 #不可变包括 字符串,元组、数值 #不可变 都返回新对象,只能调用__add__ tuple1=(20,) print(id(tuple1))#1698365629640 tuple1+=(10,20) print(id(tuple1))#1698368962632
#不可变 a=1 print(id(a))#140721907134736 a=a+2#调用_add__,返回新对象 print(id(a))#140721907134800 a+=2#调用_add__,返回新对象 print(id(a))#140721907134864
不可变对象如元组、字符串、数值加法运算,一定是调用了_add_()返回了新的对象。而可变对象如果使用+=运算,则调用__iadd__(),返回旧对象;否则调用__add__()返回新对象。
5. ==重载
使用__eq__函数重载==(其实当我们一个对象与另外一个是否相等时也是调用了__eq__函数,比如使用in判断时)。
class Vector(object): def __init__(self, x=None, y=None): self.x=x self.y=y
def __str__(self): return f"Vector({self.x,self.y})" def __eq__(self, other): #默认:按地址比较 #return id(self)==id(other) #重写:比较内容 return self.__dict__==other.__dict__ v1=Vector(1,2) v2=Vector(1,2) print(v1==v2)# print(v1.__eq__(v2))#
我们希望,如果对象的成员变量值完全相同,认为两者相等,重写__eq__时,使用return self.__dict__==other.__dict__判断。还有下面一种情况:
1 class Point(object): 2 def __init__(self, color:str,x=None, y=None): 3 self.color=color 4 self.x=x 5 self.y=y 6 7 def __str__(self): 8 return f"Vector({self.color,self.x,self.y})" 9 10 # 默认:按地址比较 11 # 重写:比较内容 12 def __eq__(self, other): 13 print(type(other))#如果下面return self.color==other这一句,第一次会打印Point类型,第二次打印str类型,自己debug一下就明白了 14 #return self.color==other.color #==两边必须是Point类型对象 15 return self.color==other #使用==时,如果左边或者右边有Point类型对象,会再次调用__eq__()函数 16 17 p1=Point('red',1,1) 18 p2=Point('red',1,2) 19 p3=Point('green',1,1) 20 21 print(p1==p2)#True 22 23 """ 24 如果使用第14行 return self.color==other.color,也可以达到print(p1==p2)同样的效果,但是不能处理下面的情况 25 """ 26 print(p1=='red')#True 只调用了一次__eq__() 27 #还有下面情况 28 lst_color=[p1,p2,p3] 29 if "red" in lst_color:#lst_color列表每个元素为Point类型对象 30 print(True) #两次输出True 31 #所以使用return self.color==other时,不仅可以判断对象是否存在与列表中,又可以判断某个成员变量是否存在于列表中
再看下面的删除操作(在上面代码后面加上如下代码):
[print(item) for item in lst_color] #运行结果的上面红色框 #再删除第一个有red的Point的对象 if "red" in lst_color: lst_color.remove("red") [print(item) for item in lst_color] #运行结果的下面红色框
结果如下(通过某个实例成员变量成功删除列表中的某个对象):
6. 大于重载
使用__gt__函数,往往用于比较两个对象或是对对象进行排序。
class Vector(object): def __init__(self, x=None, y=None): self.x=x self.y=y def __str__(self): return f"Vector({self.x,self.y})" def __gt__(self, other)->bool: return self.x>other.x list01=[Vector(1,2),Vector(3,2),Vector(0,1)] print(max(list01)) print("排序前",end=" ") for item in list01: print(item,end=" ") print() list01.sort()#升序 list01.sort(reverse=True)#逆序 print("排序后",end=" ") for item in list01: print(item,end=" ")
7. 减法重载
使用__sub__函数与__isub__函数
class Vector(object): def __init__(self, x=None, y=None): self.x=x self.y=y
def __str__(self): return f"Vector{self.x,self.y}" def __sub__(self, other): x=self.x-other.x y=self.y-other.y return Vector(x,y) def __isub__(self, other): self.x -= other.x self.y -= other.y return self v1=Vector(1,2) print(id(v1)) v1-=Vector(1,1) print(v1) print(id(v1))
小结:特表要注意__eq__()函数的用法与技巧,本文除了以上介绍的之外,还有很多,可以参考文章最后的链接,讲解的比较详细。
参考资料:
https://blog.csdn.net/weixin_42272768/article/details/124443158
https://blog.csdn.net/XQC_KKK/article/details/121889641
若存在不足或错误之处,欢迎指正与评论!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署