1. 程式人生 > 其它 >面向物件(三)繼承和多型

面向物件(三)繼承和多型

繼承

  什麼是繼承

    繼承就是新建類的一種方式,新建的類我們稱為子類或者派生類,被繼承的類稱為父類或基類。

    子類可以使用父類中的屬性或方法。

  為什麼要使用繼承

    類解決了物件和物件之間的程式碼冗餘問題。

    繼承解決了類和類之間的程式碼冗餘問題。

  如何使用繼承

    在Python2中的子類存在區別:

      新式類:繼承了object類的子子孫孫類都是新式類。

      經典類:沒有繼承了object類的子子孫孫類都是經典類。

類的繼承

# 定義一個公共的類
class People:
    def __init__(self, name, age, gender):
        self.name 
= name self.age = age self.gender = gender # 定義一個People類的子類 class Student(People): def __init__(self, name, age, gender, course=None): if course is None: course = [] # 可使用父類中的屬性或方法 People.__init__(self, name, age, gender) self.course
= course def choice_course(self, course): self.course.append(course) print('%s選課%s成功' % (self.name, self.course)) stu = Student('tom', 18, 'male', 'python') print(stu.name) # 結果為tom

屬性的查詢順序

  單繼承下的屬性查詢順序

    單繼承的情況下屬性的查詢是由子類一路向上查詢。

    在查詢時要注意引數self指的一直是呼叫方法的屬性。

class Foo:
    
def f1(self): print('Foo.f1') # 4.在Foo類中找到f2方法並執行 def f2(self): # 5.輸出Foo.f2 print('Foo.f2') # 6.此時的self指的是obj也就是Bar類 self.f1() # 3.在Bar類中找f2方法但沒找到 class Bar(Foo): # 7.執行Bar類的f1方法 def f1(self): # 8.輸出Bar.f1 print('Bar.f1') # 1.呼叫Bar類 obj = Bar() # 2.呼叫f2方法 obj.f2() # 結果: # Foo.f2 # Bar.f1

  多繼承下的屬性查詢順序

    經典類:按照深度優先的查詢順序。

    在多繼承時,經典類會一次性查到底,然後才去第二個父類找。

    新式類:按照廣度優先的查詢順序。

    在多繼承時,新式類在查到繼承object類的父類時會先不查,直到沒有其他父類才會去查詢。

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


class B(A):
    # def test(self):
    #     print('from B')
    pass


class C(A):
    # def test(self):
    #     print('from C')
    pass


class D(B):
    # def test(self):
    #     print('from D')
    pass


class E(C):
    # def test(self):
    #     print('from E')
    pass


class F(D, E):
    # def test(self):
    #     print('from F')
    pass


f1 = F()
f1.test()
# 經典類順序F->D->B->A->E->C
# 新型類順序F->D->B->E->C->A
查詢順序

super()和mro列表

  super()方法提供了除了指名道姓外另一種從父類中呼叫屬性的方式。

# 定義一個公共的類
class People:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender


# 定義一個People類的子類
class Student(People):
    def __init__(self, name, age, gender, course=None):
        if course is None:
            course = []
        # 可使用父類中的屬性或方法
        # People.__init__(self, name, age, gender)
        # super()方法在Python2中相當於super(People,self)
        # 可直接將自己傳入,不用再寫self
        super().__init__(name, age, gender)
        self.course = course

    def choice_course(self, course):
        self.course.append(course)
        print('%s選課%s成功' % (self.name, self.course))


stu = Student('tom', 18, 'male', 'python')
print(stu.name)
# 結果為tom

  super()方法的查詢順序是按照mor列表從左到右的順序進行查詢。

  因此即使沒有明顯的繼承關係,使用super()方法依然可以找到。

class A:
    # 4.A中有text開始呼叫
    def test(self):
        print('from A.test')
        # 5.super方法呼叫text,即使A並沒有父類,也會按照mor列表順序去B中找
        super().test()


class B:
    # 6.B中有text則呼叫
    def test(self):
        print('from B')


# 3.c中沒有先去父類A中找
class C(A, B):
    pass


# 1.例項化c
c = C()
# 2.查詢text
c.test()
# 結果為
# from A.test
# from B
print(C.mro())
# 結果為[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
# 因此super的查詢順序為C->A->B

多型和多型性

  多型

    多型指的是事物的不同形態。

    在現實生活中:水的形態分為液態水、冰、水蒸氣。

    在電腦中:檔案有多種形態:文字檔案,可執行檔案等。

  多型性

    多型性是指在不考慮例項型別的情況下使用例項。

    好處是能增加檔案的靈活性和可擴充套件性。

import abc


# 抽象類: 抽象類只能被繼承,不能被例項化
class Animal(metaclass=abc.ABCMeta):
    # 該方法已經是抽象方法瞭如果子類沒有對應方法會直接報錯
    @abc.abstractmethod
    def speak(self): pass


class People(Animal):
    def speak(self):
        print('嗷嗷嗷')


class Pig(Animal):
    def speak(self):
        print('哼哼哼')


class Dog(Animal):
    def speak(self):
        print('汪汪汪')


obj = People()
obj1 = Pig()
obj2 = Dog()


# 多型帶來的特性:在不用考慮物件資料型別的情況下,直接呼叫對應的函式
def animal(animal):
    return animal.speak()


animal(obj)
animal(obj1)
animal(obj2)
# 結果:
# 嗷嗷嗷
# 哼哼哼
# 汪汪汪