Python——繼承


Python的繼承是多繼承機制,一個子類可以同時有多個直接父類;繼承可以得到父類定義的方法,子類就可以復用父類的方法。

一、繼承的語法

子類:實現繼承的類。

父類(基類、超類):被繼承的類。

子類繼承父類是在定義子類時,將多個父類放在子類之后的圓括號內,如果定義類時,未指定這個類的直接父類,則默認繼承object類,所以object類是所有類的父類(直接父類或者是間接父類)。

語法格式如下:

class SubClass (SuperClassl , SuperClass2 , ... ):
    # 類定義部分

使用例子:

class Animal:
    def dog(self):
        print ('我有一只狗!他叫%s'%self.dog_name)

class Child:
    def son(self):
        print ('我有兩個兒子!')

# 定義Myself類,繼承Animal類和Child類
class Myself(Animal,Child):
    def name(self):
        print ('我叫小明!')

M = Myself()    # 創建Myself對象
M.dog_name = '大黃'   # 通過Myself對象添加dog_name類變量
M.dog() # 調用Myself對象的dog()方法,打印 我有一只狗!他叫大黃
M.son() # 調用Myself對象的son()方法,打印 我有兩個兒子!
M.name()    # 調用Myself對象的name()方法,打印 我叫小明!

在上面的例子中,定義了Animal和Child兩個父類,和一個繼承Animal類和Child類的Myself類;創建Myself對象后,可以訪問Myself對象的dog()方法和son()方法,說明Myself對象也具有dog()方法和son()方法,所以繼承可以得到父類定義的方法,通過繼承子類就可以復用父類的方法。

 

二、多繼承

子類會通過繼承得到所有父類的方法,那么如果多個父類中有相同的方法名,排在前面的父類同名方法會“遮蔽”排在后面的父類同名方法,例:

class Animal:
    def name(self):
        print ('我有一只狗,他叫大黃!')

class Child:
    def name(self):
        print ('我有兩個兒子!')

class Myself(Animal,Child):
    pass

class Yourself(Child,Animal):
    pass

M = Myself()
M.name()    # 打印 我有一只狗,他叫大黃!
Y = Yourself()
Y.name()    # 打印 我有兩個兒子!

上面例子中,Myself類繼承了Animal類和Child類,當Myself子類對象調用name()方法時,因為Myself子類中沒有定義name()方法,Python會先在Animal父類中搜尋name()方法,一旦搜尋到就會停止繼續向下搜尋,所以運行的是Animal類中的name()方法;而Yourself子類中由於Child父類排在前面,所以運行的是Child類的name()方法。

三、重寫

子類包含與父類同名的方法稱為方法重寫(方法覆蓋),可以說是重寫父類方法,也可以說子類覆蓋父類方法。

例:

class Animal:
    def name(self):
        print ('我有一只狗,他叫大黃!')


class Myself(Animal):
    # 重寫Animal類的name()方法
    def name(self):
        print ('我沒有狗,我只有一只貓,他叫大白!')


M = Myself()    # 創建Myself對象
M.name()    # 執行Myself對象的name()方法,打印 我沒有狗,我只有一只貓,他叫大白!

上面的例子中,運行M.name()時執行的不再是Animal類的fly()方法,而是Myself類的name()方法。

在子類中重寫方法之后,如果需要用到父類中被重寫的實例方法,可以通過類名調用實例方法來調用父類被重寫的方法。

例:

class Animal:
    def name(self):
        print ('我有一只狗,他叫大黃!')

class Myself(Animal):
    # 重寫Animal類的name()方法
    def name(self):
        print ('我還有一只貓,他叫大白!')

    def pet(self):
        Animal.name(self)   # 調用被重寫的父類方法name(),使用類名.實例名調用,需要手動傳self
        self.name() # 執行name()方法,會調用子類重寫的name()方法
      
  
M = Myself()    # 創建Myself對象
M.pet()
'''
打印
我有一只狗,他叫大黃!
我還有一只貓,他叫大白!
'''

  

四、super函數調用父類構造方法

如果子類有多個直接的父類,那么排在前面的構造方法會遮蔽排在后面的構造方法。

例:

class Animal:
    def __init__(self,pet,name):
        self.pet = pet
        self.name = name
        
    def favourite_animal(self):
        print ('我有一只%s,他叫%s!'%(self.pet,self.name))

class Fruit:
    def __init__(self,kind):
        self.kind = kind
        
    def favourite_fruit(self):
        print ('我喜歡的水果是%s!'%self.kind)


class Myself(Animal,Fruit):
    pass
        

M = Myself('狗','大黃')    # 創建Myself對象
M.favourite_animal()    # 調用Myself對象的favourite_animal()方法,打印 我有一只狗,他叫大黃!
M.favourite_fruit() # 調用Myself對象的favourite_fruit方法,由於未初始化Fruit對象的kind實例變量,報錯 AttributeError: 'Myself' object has no attribute 'kind'

上面例子中,Myself子類繼承了Animal父類和Fruit父類,由於Animal父類排在Fruit父類前面,所以Animal父類的構造函數遮蔽了Fruit父類的構造函數,運行M.favourite_animal()沒有任何問題,當運行M.favourite_fruit()時,由於未初始化Fruit對象的kind實例變量,所以程序會報錯。

解決以上問題,Myself應該重寫父類的構造方法,子類的構造方法可以調用父類的構造方法,有以下兩種方式:

1.使用未綁定方法,即: 父類名.__init__(self,參數1,參數2....)。

2.使用super()函數調用父類構造方法。

先查看一下super()函數的幫助信息,

>>> help(super)
Help on class super in module builtins:

class super(object)
 |  super() -> same as super(__class__, <first argument>)
 |  super(type) -> unbound super object
 |  super(type, obj) -> bound super object; requires isinstance(obj, type)
 |  super(type, type2) -> bound super object; requires issubclass(type2, type)
 |  Typical use to call a cooperative superclass method:
 |  class C(B):
 |      def meth(self, arg):
 |          super().meth(arg)
 |  This works for class methods too:
 |  class C(B):
 |      @classmethod
 |      def cmeth(cls, arg):
 |          super().cmeth(arg)
...

通過幫助信息,可以看到,當調用父類的實例方法時,會自動綁定第一個參數self;當調用類方法時,會自動綁定第一個參數cls。

接下來修改上面的程序:

class Animal:
    def __init__(self,pet,name):
        self.pet = pet
        self.name = name
        
    def favourite_animal(self):
        print ('我有一只%s,他叫%s!'%(self.pet,self.name))

class Fruit:
    def __init__(self,kind):
        self.kind = kind
        
    def favourite_fruit(self):
        print ('我喜歡的水果是%s!'%self.kind)


class Myself(Animal,Fruit):
    def __init__(self,pet,name,kind):
        Fruit.__init__(self,kind)   # 通過未綁定方法調用父類構造方法
        super().__init__(pet,name)  # 通過super()函數調用父類構造方法
        
        
               

M = Myself('狗','大黃','蘋果')
M.favourite_animal()    # 打印 我有一只狗,他叫大黃!
M.favourite_fruit()     # 打印 我喜歡的水果是蘋果!

  

 


免責聲明!

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



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