python之運算子過載

zsj.python之路發表於2018-08-28
  •     運算子過載:

        什麼是運算子過載
            讓自定義的類生成的物件(例項)能夠使用運算子進行操作
        作用:
            讓自定義的例項像內建物件一樣進行運算子操作
            讓程式簡潔易讀
            對自定義物件將運算子賦予新的規則
        算術運算子的過載:
            方法名                  運算子和表示式      說明
            __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)


        

相關文章