- 运算符重载:
什么是运算符重载
让自定义的类生成的对象(实例)能够使用运算符进行操作
作用:
让自定义的实例像内建对象一样进行运算符操作
让程序简洁易读
对自定义对象将运算符赋予新的规则
算术运算符的重载:
方法名 运算符和表达式 说明
__add__(self,rhs) self + rhs 加法
__sub__(self,rhs) self - rhs 减法
__mul__(self,rhs) self * rhs 乘法
__truediv__(self,rhs) self / rhs 除法
__floordiv__(self,rhs) self //rhs 地板除
__mod__(self,rhs) self % rhs 取模(求余)
__pow__(self,rhs) self **rhs 幂运算
示例:
class Mynumber:
def __init__(self,v):
self.data = v
def __repr__(self): #消除两边的尖括号
return "Mynumber(%d)"%self.data
def __add__(self,other):
'''此方法用来制定self + other的规则'''
v = self.data + other.data
return Mynumber(v) #用v创建一个新的对象返回给调用者
def __sub__(self,other):
'''此方法用来制定self - other的规则'''
v = self.data - other.data
return Mynumber(v)
n1 = Mynumber(100)
n2 = Mynumber(200)
# n3 = n1 + n2
n3 = n1+n2 # n3 = n1.__add__(n2)
print(n3) #Mynumber(300)
n4 = n3 - n2 #等同于n4 = n3.__sub__(n2)
print("n4 = ",n4)
rhs(right hand side) 右手边
说明:
运算符重载的方法的参数已经有了固定的含义,不建议改变原有的运算符的含义及参数的意义
二元运算符的重载方法格式:
def __xx__(self,other):
语句块
练习:
实现两个自定义列表的相加
class Mylist:
def __init__(self,iterable=()):
self.data = list(iterable)
L1 = MyList([1,2,3])
L2 = MyList([4,5,6])
L3 = L1+L2
print(L3) #MyList([1,2,3,4,5,6])
L4 = L2 + L3
print(L4) #MyList([4,5,6,1,2,3])
#试想能否实现以下操作
L5 = L1 * 3
print(L5) #MyList([1,2,3,1,2,3,1,2,3])
class Mylist:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'Mylist(%s)' % self.data
def __add__(self, lst):
return Mylist(self.data + lst.data)
def __mul__(self, rhs):
# rhs为int类型,不能用rhs.data
return Mylist(self.data * rhs)
L1 = Mylist([1, 2, 3])
L2 = Mylist([4, 5, 6])
L3 = L1 + L2
print(L3) # Mylist([1,2,3,4,5,6])
L4 = L2 + L1
print(L4) # Mylist([4,5,6,1,2,3])
L5 = L1 * 3
print(L5) # Mylist([1,2,3,1,2,3,1,2,3])
反向运算符的重载
当运算符的左侧为内建类型时,右侧为自定义类型进行算术匀算符运算时会出现TypeError错误,因为无法修改内建类型的代码 实现运算符重载,此时需要使用反向运算符的重载
反向算术运算符的重载:
方法名 运算符和表达式 说明
__radd__(self,lhs) lhs + self 加法
__rsub__(self,lhs) lhs - self 减法
__rmul__(self,lhs) lhs * self 乘法
__rtruediv__(self,lhs) lhs / self 除法
__rfloordiv__(self,lhs) lhs // self 地板除
__rmod__(self,lhs) lhs % self 取模(求余)
__rpow__(self,lhs) lhs ** self 幂运算
示例:
class Mylist:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'Mylist(%s)' % self.data
def __add__(self, lst):
print('__add__被调用')
return Mylist(self.data + lst.data)
def __mul__(self, rhs):
# rhs为int类型,不能用rhs.data
print('__mul__被调用')
return Mylist(self.data * rhs)
def __rmul__(self, lhs):
print("__rmul__被调用")
return Mylist(self.data * lhs)
L1 = Mylist([1, 2, 3])
L2 = Mylist([4, 5, 6])
L3 = 3 * L1
print(L3)
L1 += L2
print(L1)
L2 *= 3
print(L2)
复合赋值算术运算符的重载
以复合赋值算术运算符 x += y为例,此运算符会优先调用x.__iadd__(y)方法,如果没有__iadd__方法时,则会将复合赋值算术运 算拆解为:x = x + y
然后调用x = x.__add__(y)方法,如果再不存在__add__方法则会触发TypeError类型的错误异常
复合赋值算术运算符的重载:
方法名 运算符和表达式 说明
__iadd__(self,rhs) self += rhs 加法
__isub__(self,rhs) self -= rhs 减法
__imul__(self,rhs) self *= rhs 乘法
__itruediv__(self,rhs) self /= rhs 除法
__ifloordiv__(self,rhs) self //=rhs 地板除
__imod__(self,rhs) self %= rhs 取模(求余)
__ipow__(self,rhs) self **=rhs 幂运算
比较算术运算符的重载
比较算术运算符的重载:
方法名 运算符和表达式 说明
__lt__(self,rhs) self < rhs 小于
__le__(self,rhs) self <= rhs 小于等于
__gt__(self,rhs) self > rhs 大于
__ge__(self,rhs) self >= rhs 大于等于
__eq__(self,rhs) self == rhs 等于
__ne__(self,rhs) self != rhs 不等于
位运算符重载
方法名 运算符和表达式 说明
__and__(self,rhs) self & rhs 位与
__or__(self,rhs) self | rhs 位或
__xor__(self,rhs) self ^ rhs 位异或
__lshift__(self,rhs) self <<rhs 左移
__rshift__(self,rhs) self >>rhs 右移
反向位运算符重载
方法名 运算符和表达式 说明
__and__(self,lhs) lhs & rhs 位与
__or__(self,lhs) lhs | rhs 位或
__xor__(self,lhs) lhs ^ rhs 位异或
__lshift__(self,lhs) lhs <<rhs 左移
__rshift__(self,lhs) lhs >>rhs 右移
复合赋值位相关运算符重载
方法名 运算符和表达式 说明
__iand__(self,rhs) self & rhs 位与
__ior__(self,rhs) self | rhs 位或
__ixor__(self,rhs) self ^ rhs 位异或
__ilshift__(self,rhs) self <<rhs 左移
__irshift__(self,rhs) self >>rhs 右移
一元运算符的重载
方法名 运算符和表达式 说明
__neg__(self) - self 负号
__pos__(self) + self 正号
__invert__(self) ~ self 取反
语法:
class 类名:
def __xxx__(self):
pass
示例见:
class Mylist:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'Mylist(%s)' % self.data
def __neg__(self):
g = (-x for x in self.data)
return Mylist(g)
def __pos__(self):
g = (abs(x) for x in self.data)
return Mylist(g)
l1 = Mylist([1, -2, 3, -4, 5, -6])
l2 = - l1
print(l2)
l3 = +l1
print(l3)
in/not in 运算符重载
格式:
def __contains__(self,e):
语句
注: in / not in 返回布尔值 True / False
当重载了__contains__后,in和not in运算符都可用
not in 运算符的返回值与 in相反
示例:
class Mylist:
def __init__(self, iterable=()):
self.data = list(iterable)
def __repr__(self):
return 'Mylist(%s)' % self.data
def __contains__(self, e):
return True if e in self.data else False
l1 = Mylist([1, 2, 3, 4, -5, 6])
if 2 in l1: # 等同于if l1.__contains__(4)
print('2在l1内')
else:
print('2不在l1内')
if -4 not in l1: # 等同于if not l1.__contains__(4)
print('-4不在l1内')
else:
print('-4在l1内')
索引和切片运算符重载方法:
方法名 运算符和表达式 说明
__getitem__(self,i) x = self(i) 索引/切片取值
__setitem__(self,i,v) self[i] = v 索引/切片赋值
__delitem__(self,i) del self[i] del语句删除索引/切片
作用:
让自定义的类型的对象能够支持索引和切片操作
示例:
class Mylist:
def __init__(self, iterable=()):
self.__data = list(iterable)
def __repr__(self):
return 'Mylist(%s)' % self.__data
def __getitem__(self, i):
'索引取值,i绑定[]内的元素'
print('i的值', i)
return self.__data[i] # 返回data绑定列表中的第i个元素
def __setitem__(self, i, v):
'''此方法可以让自定义的列表支持索引赋值操作'''
print('__setitem__被调用,i = ', i, 'v = ', v)
self.__data[i] = v
def __delitem__(self, i):
del self.__data[i] # self.__data.pop(i)
return self
if type(i) is int:
print('用户正在用索引取值')
elif type(i) is slice:
print('用户正在用切片取值')
print('切片的起点是:', i.start)
print('切片的终点是:', i.stop)
print('切片的步长是:', i.step)
elif type(i) is str:
print('用户正在用字符串进行索引操作')
# raise KeyError
return self.__data[i] # 返回data绑定的第i个元素
l1 = Mylist([1, 2, 3, 4, -5, 6])
print(l1[3]) # 4
l1[3] = 400
print(l1) # Mylist([1, 2, 3, 400, -5, 6])
del l1[3]
print(l1) # Mylist([1, 2, 3, -5, 6])
print(l1[::2]) # [1,3,6]
slice构造函数
作用:
用于创建一个slice对象,此对于用于切片操作的传值
格式:
slice(start = None,stop = None ,step = None)
slice对象的实例属性:
start 切片的起始值,默认为None
stop 切片的终止值,默认为None
step 切片的步长,默认为None
特性属性@property
实现其他语言所拥有的getter和setter功能
作用:
用来模拟一个属性
通过@property装饰器,可以对模拟属性的赋值和取值加以控制
示例:
class Student:
def __init__(self, s):
self.__score = s
@property
def score(self):
print('getter被调用')
return self.__score
@score.setter
def setScore(self, s):
'''此方法用设置值加以限制以保证数据的准确性setter是用来数据的'''
if 0 <= s <= 100:
self.__score = s
def getScore(self, s):
'''getter只是用来获取数据'''
return self.__score
s = Student(20)
# s.setScore(100)
score = s.score
print('成绩是:', score)