python面向對象之繼承


2. 繼承

繼承的第一個作用

第一階段:繼承的作用

class Animal(object):
    def run(self):
        print("Animal is running")

class Dog(Animal):
    pass

class Cat(Animal):
    pass

dog = Dog()
cat = Cat()

dog.run()
cat.run()
Animal is running
Animal is running

上面Animal就是父類,子類就是Dog和Cat,因為Dog和Cat繼承了Animal,子類會擁有父類的所有方法。

總結:

​ 1. 當子類繼承父類后,子類就會擁有父類的所有方法

繼承的第二個作用:子類重寫方法后,優先調用子類方法

第二階段:當子類繼承父類后,子類寫了一個run方法,父類也寫了一個run方法,子類調用run方法時,應該調用父類的run還是子類的?

# 子類繼承父類的方法
class Animal(object):
    def run(self):
        print("Animal is running")

class Dog(Animal):
    def run(self):
        print("Dog is running")

class Cat(Animal):
    def run(self):
        print("Cat is running")

dog = Dog()
cat = Cat()

# 調用方法
dog.run()
cat.run()
Dog is running
Cat is running

由此可以看出,優先調用子類的方法

總結:

​ 1. 當子類擁有和父類相同的方法時,優先調用子類的方法。

繼承的第三個作用:類的派生

class person(object):
    def __init__(self, weight):
        self.weight = weight

    def eat(self):
        print("正在吃東西")


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

a = Student('plf', 18, '男')
a.eat()
print(a.name, a.age, a.sex)
正在吃東西
plf 18 男

對於以上的代碼,提出一個疑問:既然Student類繼承了person類,那么Student初始化的對象就擁有了person類的方法,但是對應person的屬性weight,Student似乎沒有繼承到,那么我們如何在初始化Student對象時,擁有父類的weight屬性?同時擁有不同於父類的屬性?

class person(object):
    def __init__(self,weight):
        self.weight = weight

class Student(person):
    def __init__(self,name,age,sex,weight):
        self.name = name
        self.age = age
        self.sex = sex
        super().__init__(weight)		# 調用了父類的__init__方法,並將weight傳給了person


a = Student('plf',18,'男',140)
print(a.name,a.age,a.sex,a.weight)

因此想要得到父類的屬性,必須要在子類的初始化方法中(__init__函數)中調用父類的方法:super()._init_(args,*kwargs) 這樣就能拿到父類的屬性並賦值 最后變成自己的屬性,同時子類有不同於父類的屬性。子類繼承父類,子類有父類的屬性,且子類有不同於父類的屬性,那么這一過程我們成為類的派生

經典類和新式類

什么是經典類 什么事是新式類

'''
Python 2 當中類分為新式類和經典類 
Python 3中全部叫新式類  
python 2中如果有繼承父類是object 就是新式類,繼承其他類不算,但是如果繼承其他類,其他類有其他了object 那就是新式類
'''

# 經典類
class 類名:
    pass

# 新式類
class 類名(object):
    pass

經典類的繼承特點:深度優先

新式類的繼承特點:廣度優先

使用代碼證明

class G(object):
    def test(self):
        print('from G')

class E(G):
    def test(self):
        print('from E')

class F(G):
    def test(self):
        print('from F')

class B(E):
    def test(self):
        print('from B')

class C(F):
    def test(self):
        print('from C')

class D(G):
    def test(self):
    	print('from D')
       
class A(B,C,D):
    def test(self):
        print('from A')
a=A()
a.test()
print(A.__mro__) #只有新式才有這個屬性可以查看線性列表,經典類沒有這個屬性

#新式類繼承順序:A->B->E->C->F->D->G
#經典類繼承順序:A->B->E->G->C->F->D

#python3中統一都是新式類
#pyhon2中才分新式類與經典類
from A
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>)

繼承原理(python如何實現的繼承)python2中沒有_mro_

python到底是如何實現繼承的,對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,例如

>>> A.mro() #等同於A.__mro__
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class '__main__.G'>, <class 'object'>)

為了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。
而這個MRO列表的構造是通過一個C3線性化算法來實現的。我們不去深究這個算法的數學原理,它實際上就是合並所有父類的MRO列表並遵循如下三條准則:

1.子類會先於父類被檢查
2.多個父類會根據它們在列表中的順序被檢查
3.如果對下一個類存在兩個合法的選擇,選擇第一個父類


免責聲明!

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



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