繼承


1.什么面向對象的繼承?

比較官方的說法就是:

繼承(英語:inheritance)是面向對象軟件技術當中的一個概念。如果一個類別A“繼承自”另一個類別B,就把這個A稱為“B的子類別”,而把B稱為“A的父類別”也可以稱“B是A的超類”。繼承可以使得子類別具有父類別的各種屬性和方法,而不需要再次編寫相同的代碼。

那么用一個例子來看一下繼承:

class Person:
    def __init__(self,name,sex,age):
        self.name = name
        self.age = age
        self.sex = sex

class Cat:
    def __init__(self,name,sex,age):
        self.name = name
        self.age = age
        self.sex = sex

class Dog:
    def __init__(self,name,sex,age):
        self.name = name
        self.age = age
        self.sex = sex

# 繼承的用法:
class Aniaml(object):
    def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex

class Person(Aniaml):
    pass

class Cat(Aniaml):
    pass

class Dog(Aniaml):
    pass

繼承的有點也是顯而易見的:

1,增加了類的耦合性(耦合性不宜多,宜精)。

2,減少了重復代碼。

3,使得代碼更加規范化,合理化。

2.繼承的分類

就向上面的例子:

Aminal 叫做父類,基類,超類。
Person Cat Dog: 子類,派生類。
繼承:可以分單繼承,多繼承

這里需要補充一下python中類的種類(繼承需要):

在python2x版本中存在兩種類.:
  ⼀個叫經典類. 在python2.2之前. ⼀直使⽤的是經典類. 經典類在基類的根如果什么都不寫.
  ⼀個叫新式類. 在python2.2之后出現了新式類. 新式類的特點是基類的根是object類。
python3x版本中只有一種類:
python3中使⽤的都是新式類. 如果基類誰都不繼承. 那這個類會默認繼承 object

3.單繼承

3.1 類名,對象執行父類方法

類名,對象分別調用父類方法

class Aniaml(object):
    type_name = '動物類'

    def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex

    def eat(self):
        print(self)
        print('吃東西')

class Person(Aniaml):
    pass

class Cat(Aniaml):
    pass

class Dog(Aniaml):
    pass
# 類名:
print(Person.type_name)  # 可以調用父類的屬性,方法。
Person.eat(111)
print(Person.type_name)

# 對象:
# 實例化對象
p1 = Person('春哥','男',18)
print(p1.__dict__)
# 對象執行類的父類的屬性,方法。
print(p1.type_name)
p1.type_name = '666'
print(p1)
p1.eat()

3.2 執行順序

class Aniaml(object):
    type_name = '動物類'
    def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex

    def eat(self):
        print(self)
        print('吃東西')

class Person(Aniaml):
    
    def eat(self):
        print('%s 吃飯'%self.name)
        
class Cat(Aniaml):
    pass

class Dog(Aniaml):
    pass

p1 = Person('barry','男',18)
# 實例化對象時必須執行__init__方法,類中沒有,從父類找,父類沒有,從object類中找。
p1.eat()
# 先要執行自己類中的eat方法,自己類沒有才能執行父類中的方法。

執行順序

3.3同時執行類以及父類方法

方法一:

如果想執行父類的func方法,這個方法並且子類中夜用,那么就在子類的方法中寫上:

父類.func(對象,其他參數)

舉例說明:

class Aniaml(object):
    type_name = '動物類'
    def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex

    def eat(self):
        print('吃東西')

class Person(Aniaml):
    def __init__(self,name,sex,age,mind):
        '''
        self = p1
        name = '春哥'
        sex = 'laddboy'
        age = 18
        mind = '有思想'
        '''
        # Aniaml.__init__(self,name,sex,age)  # 方法一
        self.mind = mind

    def eat(self):
        super().eat()
        print('%s 吃飯'%self.name)
class Cat(Aniaml):
    pass

class Dog(Aniaml):
    pass

# 方法一: Aniaml.__init__(self,name,sex,age)
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)

# 對於方法一如果不理解:
# def func(self):
#     print(self)
# self = 3
# func(self)

方法二:

利用super,super().func(參數)

class Aniaml(object):
    type_name = '動物類'
    def __init__(self,name,sex,age):
            self.name = name
            self.age = age
            self.sex = sex

    def eat(self):
        print('吃東西')

class Person(Aniaml):
    def __init__(self,name,sex,age,mind):
        '''
        self = p1
        name = '春哥'
        sex = 'laddboy'
        age = 18
        mind = '有思想'
        '''
        # super(Person,self).__init__(name,sex,age)  # 方法二
        super().__init__(name,sex,age)  # 方法二
        self.mind = mind

    def eat(self):
        super().eat()
        print('%s 吃飯'%self.name)
class Cat(Aniaml):
    pass

class Dog(Aniaml):
    pass
# p1 = Person('春哥','laddboy',18,'有思想')
# print(p1.__dict__)

單繼承練習題:

# 1
class Base:
    def __init__(self, num):
        self.num = num
    def func1(self):
        print(self.num)

class Foo(Base):
    pass
obj = Foo(123)
obj.func1() # 123 運⾏的是Base中的func1  

# 2      
class Base:
    def __init__(self, num):
        self.num = num
    def func1(self):
        print(self.num)
class Foo(Base):
    def func1(self):
        print("Foo. func1", self.num)
obj = Foo(123)
obj.func1() # Foo. func1 123 運⾏的是Foo中的func1       

# 3         
class Base:
    def __init__(self, num):
        self.num = num
    def func1(self):
        print(self.num)
class Foo(Base):
    def func1(self):
        print("Foo. func1", self.num)
obj = Foo(123)
obj.func1() # Foo. func1 123 運⾏的是Foo中的func1     
# 4
class Base:
    def __init__(self, num):
        self.num = num
    def func1(self):
        print(self.num)
        self.func2()
    def func2(self):
        print("Base.func2")
class Foo(Base):
    def func2(self):
    print("Foo.func2")
obj = Foo(123)
obj.func1() # 123 Foo.func2 func1是Base中的 func2是⼦類中的 
# 再來
class Base:
    def __init__(self, num):
        self.num = num
    def func1(self):
        print(self.num)
        self.func2()
    def func2(self):
        print(111, self.num)
class Foo(Base):
    def func2(self):
        print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
    obj.func2() # 111 1 | 111 2 | 222 3

# 再來
class Base:
    def __init__(self, num):
        self.num = num
    def func1(self):
        print(self.num)
        self.func2()
    def func2(self):
        print(111, self.num)
class Foo(Base):
    def func2(self):
        print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
 obj.func1() # 那筆來吧. 好好算
                          

4.多繼承

class ShenXian: # 神仙
    def fei(self):
        print("神仙都會⻜")
class Monkey: # 猴
    def chitao(self):
        print("猴⼦喜歡吃桃⼦")
class SunWukong(ShenXian, Monkey): # 孫悟空是神仙, 同時也是⼀只猴
    pass
sxz = SunWukong() # 孫悟空
sxz.chitao() # 會吃桃⼦
sxz.fei() # 會⻜

  此時, 孫悟空是⼀只猴⼦, 同時也是⼀個神仙. 那孫悟空繼承了這兩個類. 孫悟空⾃然就可以執⾏這兩個類中的⽅法. 多繼承⽤起來簡單. 也很好理解. 但是多繼承中, 存在着這樣⼀個問題. 當兩個⽗類中出現了重名⽅法的時候. 這時該怎么辦呢? 這時就涉及到如何查找⽗類⽅法的這么⼀個問題.即MRO(method resolution order) 問題. 在python中這是⼀個很復雜的問題. 因為在不同的python版本中使⽤的是不同的算法來完成MRO的.

這里需要補充一下python中類的種類(繼承需要):

在python2x版本中存在兩種類.:
  ⼀個叫經典類. 在python2.2之前. ⼀直使⽤的是經典類. 經典類在基類的根如果什么都不寫.
  ⼀個叫新式類. 在python2.2之后出現了新式類. 新式類的特點是基類的根是object類。
python3x版本中只有一種類:
python3中使⽤的都是新式類. 如果基類誰都不繼承. 那這個類會默認繼承 object

4.1經典類的多繼承

雖然在python3中已經不存在經典類了. 但是經典類的MRO最好還是學⼀學. 這是⼀種樹形結構遍歷的⼀個最直接的案例. 在python的繼承體系中. 我們可以把類與類繼承關系化成⼀個樹形結構的圖. 來, 上代碼:

class A:
    pass
class B(A):
    pass
class C(A):
    pass
class D(B, C):
    pass
class E:
    pass
class F(D, E):
    pass
class G(F, D):
    pass
class H:
    pass
class Foo(H, G):
    pass

代碼示例

對付這種mro畫圖就可以:

繼承關系圖已經有了. 那如何進⾏查找呢? 記住⼀個原則. 在經典類中采⽤的是深度優先,遍歷⽅案. 什么是深度優先. 就是⼀條路走到頭. 然后再回來. 繼續找下⼀個.

圖中每個圈都是准備要送雞蛋的住址. 箭頭和⿊線表⽰線路. 那送雞蛋的順序告訴你入⼝在最下⾯R. 並且必須從左往右送. 那怎么送呢?

如圖. 肯定是按照123456這樣的順序來送. 那這樣的順序就叫深度優先遍歷. ⽽如果是142356呢? 這種被稱為⼴度優先遍歷. 好了. 深度優先就說這么多. 那么上⾯那個圖怎么找的呢? MRO是什么呢? 很簡單. 記住. 從頭開始. 從左往右. ⼀條路跑到頭, 然后回頭. 繼續⼀條路跑到頭. 就是經典類的MRO算法.

類的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C. 你猜對了么?

4.2新式類的多繼承

4.2.1 mro序列

MRO是一個有序列表L,在類被創建時就計算出來。
通用計算公式為:

mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child繼承自Base1, Base2)

如果繼承至一個基類:class B(A)
這時B的mro序列為

mro( B ) = mro( B(A) )
= [B] + merge( mro(A) + [A] )
= [B] + merge( [A] + [A] )
= [B,A]

如果繼承至多個基類:class B(A1, A2, A3 …)
這時B的mro序列

mro(B) = mro( B(A1, A2, A3 …) )
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
= ...

計算結果為列表,列表中至少有一個元素即類自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。

4.2.2. 表頭和表尾
表頭:
  列表的第一個元素

表尾:
  列表中表頭以外的元素集合(可以為空)

示例
  列表:[A, B, C]
  表頭是A,表尾是B和C

4.2.3. 列表之間的+操作
+操作:

[A] + [B] = [A, B]
(以下的計算中默認省略)
---------------------

merge操作示例:

'''
如計算merge( [E,O], [C,E,F,O], [C] )
有三個列表 :

1 merge不為空,取出第一個列表列表①的表頭E,進行判斷                              
   各個列表的表尾分別是[O], [E,F,O],E在這些表尾的集合中,因而跳過當前當前列表
2 取出列表②的表頭C,進行判斷
   C不在各個列表的集合中,因而將C拿出到merge外,並從所有表頭刪除
   merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
3 進行下一次新的merge操作 ......
--------------------- 
'''

計算mro(A)方式:

mro(A) = mro( A(B,C) )

原式= [A] + merge( mro(B),mro(C),[B,C] )

  mro(B) = mro( B(D,E) )
         = [B] + merge( mro(D), mro(E), [D,E] )  # 多繼承
         = [B] + merge( [D,O] , [E,O] , [D,E] )  # 單繼承mro(D(O))=[D,O]
         = [B,D] + merge( [O] , [E,O]  ,  [E] )  # 拿出並刪除D
         = [B,D,E] + merge([O] ,  [O])
         = [B,D,E,O]

  mro(C) = mro( C(E,F) )
         = [C] + merge( mro(E), mro(F), [E,F] )
         = [C] + merge( [E,O] , [F,O] , [E,F] )
         = [C,E] + merge( [O] , [F,O]  ,  [F] )  # 跳過O,拿出並刪除
         = [C,E,F] + merge([O] ,  [O])
         = [C,E,F,O]

原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
    = [A,B] + merge( [D,E,O], [C,E,F,O],   [C])
    = [A,B,D] + merge( [E,O], [C,E,F,O],   [C])  # 跳過E
    = [A,B,D,C] + merge([E,O],  [E,F,O])
    = [A,B,D,C,E] + merge([O],    [F,O])  # 跳過O
    = [A,B,D,C,E,F] + merge([O],    [O])
    = [A,B,D,C,E,F,O]
--------------------- 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM