Python基礎(chǔ)33-面向?qū)ο?繼承資源(屬性與方法)的使用注意)

在Python中, 繼承是指子類對父類資源的使用權(quán)

1 繼承-屬性與方法的使用權(quán)限

1.1 測試屬性與方法分別如下

  • 公有屬性/方法
  • 受保護(hù)屬性/方法
  • 私有屬性/方法
class Animal:
    a = 1 # 公有屬性
    _b = 2 # 受保護(hù)屬性
    __c = 3 # 私有屬性

    #公有方法
    def t1(self):
        print("t1")

    # 受保護(hù)方法
    def _t2(self):
        print("t2")
    
    # 私有方法
    def __t3(self):
        print("t3")
    # 內(nèi)置方法
    def __init__(self):
        print("init, Animal")


class Person(Animal):

    # 在實(shí)例對象(子類)內(nèi)對以上屬性及方法的訪問權(quán)限
    def test(self):
        print(id(self.a)) # 打印地址的目的是為了證明子類對父類屬性繼承是`可以使用`,而非`擁有副本`
        print(self.a)
        print(self._b)
        # print(self.__c) # 不能訪問私有屬性

        self.t1()
        self._t2()
        # self.__t3() # 不能訪問私有方法
        self.__init__() 

p = Person()
p.test()

print(id(Animal.a))
p.test()

>>>> 打印結(jié)果
init, Animal
4502964848
1
2
t1
t2
init, Animal
4502964848
4502964848
1
2
t1
t2
init, Animal

除私有的屬性和私有的方法, 其他屬性和方法子類基本都能繼承(具有使用權(quán))

2 繼承-通過子類給父類屬性進(jìn)行賦值時(shí),默認(rèn)是指給之類增加一個(gè)與父類同名的屬性

class Father:
    age = 10


class Son(Father):
    pass


print(Son.age) # 訪問父類屬性
Son.age = 9 # 給子類增加與父類同名屬性

print(Son.age)

print(Father.age)
print(Son.__dict__)
print(Father.__dict__)

>>>>打印結(jié)果
10
9
10
{'__module__': '__main__', '__doc__': None, 'age': 9}
{'__module__': '__main__', 'age': 10, '__dict__': <attribute '__dict__' of 'Father' objects>, '__weakref__': <attribute '__weakref__' of 'Father' objects>, '__doc__': None}

3 繼承的3種形態(tài)

繼承的3種形態(tài)

4 幾種形態(tài)應(yīng)該遵循的標(biāo)準(zhǔn)原則

4.1 單繼承

  • 遵循"從下到上的原則"
  • 自己身上沒有這個(gè)資源, 就到父類里面去找,父類里面沒有再往上找

4.2 無重疊的多繼承

  • 遵循"單調(diào)原則"
  • 按照繼承的先后順序,優(yōu)先調(diào)用左側(cè)繼承鏈上的資源

4.3 有重疊的多繼承

  • 遵循"從下到上的原則"
  • 簡單理解就是:
  1. A繼承B繼承C
  2. B重寫了C類的方法, 那么A優(yōu)先使用B類的方法

4 查看類的資源查找順序方法

通過inspect模塊進(jìn)行

目的:假如繼承鏈中多個(gè)父類重寫的資源,要學(xué)會查找哪些類的重寫資源會被優(yōu)先調(diào)用

# 導(dǎo)入資源查看模塊 inspect
import inspect


class D(object):
    pass

class B(D):
    pass


class C(D):
    pass

class A(B, C):
    pass

# 方法一
print(inspect.getmro(A))

# 方法二
print(A.__mro__)

# 方法三
print(A.mro())

>>>>打印結(jié)果

(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]

TODO:《 針對于幾種標(biāo)準(zhǔn)原則的方案演化》

  1. 不同 Python 版本 MRO 原則
  2. 菱形繼承鏈問題

5 資源覆蓋(MRO 優(yōu)先級高的優(yōu)先調(diào)用)

5.1 原理

  1. 基于MRO的資源檢索鏈
  2. 優(yōu)先級高的類具有一個(gè)與優(yōu)先級低的類一樣的一個(gè)資源(屬性或方法)
  3. 會先選擇優(yōu)先級高的資源 ,而摒棄優(yōu)先級低的資源(造成"覆蓋"的假象)
class D(object):
    age = "d"
    pass

class C(D):
    age = "c"
    def test(self):
        print("c")
    pass

class B(D):
    # age = "b"
    def test(self):
        print("b")
    pass

class A(B, C):
    pass

a = A()
a.test()

print(A.mro())

print(A.age)
print(A().test())

>>>>打印結(jié)果
b
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
c
b
None

5.2 調(diào)用優(yōu)先級高資源時(shí),self 與 cls 的變化

結(jié)論:誰調(diào)用,就是誰

class D(object):
    pass

class C(D):
    def test(self):
        print(self)
    pass

class B(D):
    def test(self):
        print(self)

    @classmethod
    def test2(cls):
        print(cls)
    pass

class A(B, C):
    pass

A.test2()

a = A()
a.test()

>>>>打印結(jié)果

<class '__main__.A'>
<__main__.A object at 0x1011b79b0>

6 在低優(yōu)先級類的方法中,通過"super"調(diào)用高優(yōu)先級類的方法

  • Python3.x
class B:
    a = 1

    def __init__(self):
        self.b = 2
        self.xxx = "123"

    def t1(self):
        print("t1")

    @classmethod
    def t2(cls):
        print(cls)
        print("t2")

    @staticmethod
    def t3():
        print("t3")


class A(B):
    c = 3

    def __init__(self):
        super().__init__()
        self.e = "666"

    def tt1(self):
        print("tt1")

    @classmethod
    def tt2(cls):
        super().t2()
        print("tt2")

    @staticmethod
    def tt3():
        print("tt3")

    pass

a = A()
print(a.__dict__)

print("-" * 20)
A.tt2()

>>>>打印結(jié)果
{'b': 2, 'xxx': '123', 'e': '666'}
--------------------
<class '__main__.A'>
t2
tt2
  • Python2.2+
class B:
    a = 1

    def __init__(self):
        self.b = 2
        self.xxx = "123"

    def t1(self):
        print("t1")

    @classmethod
    def t2(cls):
        print(cls)
        print("t2")

    @staticmethod
    def t3():
        print("t3")


class A(B):
    c = 3

    def __init__(self):
        super(A, self).__init__()
        self.e = "666"

    def tt1(self):
        print("tt1")

    @classmethod
    def tt2(cls):
        super(A, cls).t2()
        print("tt2")

    @staticmethod
    def tt3():
        print("tt3")

    pass

a = A()
print(a.__dict__)

print("-" * 20)
A.tt2()

>>>>打印結(jié)果
{'b': 2, 'xxx': '123', 'e': '666'}
--------------------
<class '__main__.A'>
t2
tt2

注意

  1. super 和父類(超類)沒有實(shí)質(zhì)性的關(guān)聯(lián)
    僅僅是沿著MRO鏈條, 找到下一級節(jié)點(diǎn)
  2. 保證調(diào)用形式的統(tǒng)一
    要是類名調(diào)用, 全是類名調(diào)用
    要是super調(diào)用, 全是super調(diào)用
    (混合使用容易出現(xiàn)死循環(huán))
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容