1. 程式人生 > >(D19)Python-封裝、多型、多繼承、重寫

(D19)Python-封裝、多型、多繼承、重寫



封裝 enclosure

  • 封裝是指隱藏類的實現細節,讓使用者不用關心這些細節
  • 封裝的目的是讓使用者通過儘可能少的方法(或屬性)操作物件

私有屬性和方法:

  • python類中以雙下劃線(’__’)開頭,不以雙下劃線結尾的識別符號為私有成員,私有成員只能用此類的方法進行訪問和修改

示例1:


# 此示例示意用私有屬性和私有方法來進行封裝
class A:
    def __init__(self):
        self.__p1 = 100  # 建立私有屬性,此屬性在類外無法訪問
 
    def __m1(self):  # 私有方法
        print("__m1 私有方法被呼叫")
 
    def infos(self):
        print("A類的infos訪問的__p1屬性是:", self.__p1)
        self.__m1()  # 呼叫自己的私有方法
    
a = A()
# print(a.__p1)  # 出錯
a.infos()
# a.__m1()  # 當前主模組不能呼叫A類的私有方法


多型 polymorphic

  • 什麼是多型:

    • 字面意思: 多種狀態
  • 狀態:

    • 靜態(編譯時狀態)
    • 動態(執行時狀態)
  • 多型是指在有繼承/派生關係的類中,呼叫基類物件的方法,呼叫基類物件的方法,實際能呼叫子類的覆蓋方法的現象叫多型

  • 說明:

    • 多型呼叫的方法與物件相關,不與型別相關
    • python全部物件都只有執行時狀態(動態)
    • 沒有"c++語言"裡編譯時狀態(靜態)

示例2:


# 此示例示意python的多型(動態)
class Shape:
    '''圖形'''
    def draw(self):
        print("Shape的draw() 被呼叫")
 
class Point(Shape):
    def draw(self):
        print("正在畫一個點")
 
class Circle(Point):
    def draw(self):
        print("正在畫一個圓")
        
def my_draw(s):
    s.draw()  # s.draw呼叫誰是在執行時由s的型別動態決定
              # 此處顯示出執行時狀態
 
shape1 = Circle()
shape2 = Point()
my_draw(shape1)
my_draw(shape2)
 
L = [Point(), Circle(), Point(), Point(), Circle()]
 
for s in L:

面向物件的程式語言的特徵

封裝
繼承/派生
多型

多繼承 multiple inheritance

  • 多繼承是指一個子類繼承自兩個或兩個以上的基類

語法:
- class 類名(基類名1,基類名2,…)
說明:

  • 一個子類同時繼承自多個父類,父類中的方法可以同時被繼承下來
    如果兩個父類中有同名的方法,則在子類中又沒有覆蓋此方法時,
    呼叫結果難以確定
    示例3:

# 此示例示意多繼承的語法和用法
class Car:
    def run(self, speed):
        print('車正在以', speed, '公里/小時的速度行駛')
 
class Plane:
    def fly(self, height):
        print('飛機以海拔', height, '米的高空飛行')
 
class PlaneCar(Plane, Car):
    '''PlaneCar類同時繼承是Plane和 Car類'''
 
p1 = PlaneCar()
p1.fly(10000)

多繼承的問題(缺陷)

  • 識別符號(名字空間)衝突問題
  • 要謹慎使用多繼承

多繼承的MRO(Method Resolution Order)等問題

  • 類的__mro__屬性:
    • 作用:
      • 用來記錄屬性(或方法)的查詢順序

函式重寫 overwrite

什麼是函式重寫

  • 在自定義的類內新增相應的方法,讓自定義的類生成的物件(例項)
  • 像內建物件一樣進行函式操作

物件轉字串函式:

  • repr(x) 返回一個能代表此物件的表示式字串,通常:
    • eval(repr(obj)) = obj
  • str(obj) 通過給定物件,返回一個字串(這個字串通常是給人閱讀的)

示例4:

# 此示例示意repr函式和str函式的不同
s = "I'm Teacher"
print(str(s))  
print(repr(s))
 
 
class MyNumber:
    def __init__(self,value):
        self.data = value
    def __str__(self):
        print("正在呼叫__str__方法,轉換為普通字串")
        s = "自定義資料%d" % self.data
        return s
  
    def __repr__(self):
        return 'MyNumber(%d)' % self.data
 
n1 = MyNumber(100)
print(str(n1))
print(repr(n1))


# 此示例示意自定義的物件轉為python內鍵的數字型別
class MyNumber:
    def __init__(self, v):
        self.data = v
    def __repr__(self):
        return "MyNumber(%d)" % self.data
    def __int__(self):
        return int(self.data)
 
n1 = MyNumber(100.5)
n = int(n1)  # 自定義型別轉為整數, 出錯!!!
print(n)

str(obj) 函式呼叫方法說明:

  1. str(obj) 函式先查詢obj.__str__()方法,呼叫此方法並返回結果
  2. 如果obj.__str__() 方法不存在,則呼叫obj.__repr__()方法並返回結果
  3. 如果obj.__repr__方法不存在,則呼叫object類的__repr__例項方法顯示
    <__main__.MyNumber object at xxx>格式的字串

內建函式重寫

    __abs__         abs(obj) 函式呼叫
    __len__         len(obj) 函式呼叫
    __reversed__   reversed(obj) 函式呼叫
    __round__       round(obj) 函式呼叫

示例5


# 此示例示意 abs 和len方法的重寫方法
 
class MyInteger:
    def __init__(self, v):
        self.data = v
 
    def __repr__(self):
        return 'MyInteger(%d)' % self.data
 
    def __abs__(self):
        '''此方法用於制定abs(obj) 函式取值時返回的結果'''
        if self.data < 0:
            # 用-self.data 建立一個新的物件返回回去
            t = MyInteger(-self.data)
            return t
        return MyInteger(self.data)
 
i1 = MyInteger(-100)
 
print(i1)  # 等同於print(str(i1)) 
n = abs(i1)
print(n)  # MyInteger(100)
 
i2 = MyInteger(200)
print(abs(i2))  # MyInteger(200)

數值轉換函式重寫

    __complex__     coplex(obj)  函式呼叫
    __int__         int(obj)  函式呼叫
    __float__       float(obj)  函式呼叫
    __bool__        bool(obj)  函式呼叫

示例6


# 此示例示意自定義的物件轉為python內鍵的數字型別
class MyNumber:
    def __init__(self, v):
        self.data = v
    def __repr__(self):
        return "MyNumber(%d)" % self.data
    def __int__(self):
        return int(self.data)
 
n1 = MyNumber(100.5)
n = int(n1)  # 自定義型別轉為整數, 出錯!!!
print(n)

布林測試函式重寫

  • 格式:
    • def bool(self):

作用:

  • 用於bool(obj)函式取值
  • 用於if語句真值表達式中
  • 用於while語句的值表示式中

說明:

  • 1.當自定義類有__bool__(self)方法時,以此方法的返回值作為bool(obj)的返回值
    1. 當不存在__bool__(self)方法時,bool(x)返回__len__(self)方法的返回值是否為零來測試布林值
  • 3.當再不存在__len__(self)方法時,則直接返回True

示例7:

# 此示例示意__bool__方法的重寫方法及用法
 
class MyList:
    def __init__(self, iterable=()):
        self.data = [x for x in iterable]
 
    def __repr__(self):
        return "MyList(%s)" % self.data
 
    def __len__(self):
        print("__len__被呼叫")
        return len(self.data)
    def __bool__(self):
        '''此方法用來制定一個bool(x) 返回的規則'''
        # 如果沒有任何元素返回False
        print("__bool__方法被呼叫")
        if len(self.data) == 0:
            return False
        for x in self.data:
            if x:
                return True
        return False
 
myl = MyList([1, -2, 3, -4])
# myl = MyList()
print(myl)
print(bool(myl))  # False
print(len(myl))
 
myl1 = MyList([0, 0.0, False, None])    
print(bool(myl1))  # False
 
myl2 = MyList([0, 1, 2])
print(bool(myl2))  # True