1. 程式人生 > 其它 >多型於多型性與鴨子型別

多型於多型性與鴨子型別

一:多型與多型性

多型:
同一種事物有多種形態
動物有多種形態:如狗、貓、豬

class Animal:    # 同一類事物:動物
  def talk(self):
        pass
    
class Dog(Animal):  # 動物的形態之一:狗
    def talk(self):       
        print("汪汪汪")

class Cat(Animal):  # 動物的形態之二:貓
    def talk(self):
        print('喵喵!')

class Pig(Animal):  # 動物的形態之一:豬
    def talk(self):
        print("哼哼哼!")

例項化得到三個物件

obj1 = Dog()
obj2 = Cat()
obj3 = Pig()

父類的功能是用來統一子類的,定標準的,只要看父類功能就知道子類也有

多型性指的是可以在不用考慮物件具體型別的情況下而直接使用物件,這就需要在設計時,把物件的使用方法統一成一種:例如obj1、obj2、obj3都是動物,但凡是動物肯定有talk方法,於是我們可以不用考慮它們三者的具體是什麼型別的動物,而直接使用
obj1.talk()

汪汪汪

obj2.talk()

喵喵!

obj3.talk()

哼哼哼!

在多型性背景下用的繼承,父類的功能其實不是真的拿來給子類用的,而是用來給子類定標準的,用來統一子類的,只需要把父類的功能規定好了,子類就肯定有,這樣的好處是隻要看父類就知道子類有什麼功能
更進一步,我們可以定義一個統一的介面來使用
def talk(animal): # 定義一個函式talk 傳進來引數就叫動物
animal.talk() # 只要是動物就肯定有talk方法

三個物件統一用一個函式talk去調,用起來統一了

talk(obj1)
talk(obj2)
talk(obj3)
綜上我們得知,多型性的本質在於不同的類中定義有相同的方法名,這樣我們就可以不考慮類而統一用一種方式去使用物件,可以通過在父類引入抽象類的概念來硬性限制子類必須有某些方法名
import abc

指定metaclass屬性將類設定為抽象類,抽象類本身只是用來約束子類的,不能被例項化

class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod # 該裝飾器限制子類必須定義有一個名為talk的方法
def talk(self): # 抽象方法中無需實現具體的功能
pass

class Dog(Animal): # 但凡繼承Animal的子類都必須遵循Animal規定的標準
def talk(self):
print("汪汪汪")

class Cat(Animal):
def talk(self):
print('喵喵!')

class Pig(Animal):
def tell(self): # 若子類中沒有一個名為talk的方法則會丟擲異常TypeError,無法例項化
print("哼哼哼!")

obj1 = Dog()
obj2 = Cat()
obj3 = Pig()

obj1.talk()
obj2.talk()
obj3.talk()

但其實我們完全可以不依賴於繼承,只需要製造出外觀和行為相同物件,同樣可以實現不考慮物件型別而使用物件,這正是Python崇尚的“鴨子型別”(duck typing):“如果看起來像、叫聲像而且走起路來像鴨子,那麼它就是鴨子”。比起繼承的方式,鴨子型別在某種程度上實現了程式的鬆耦合度,如下

三者看起來都像,三者都有talk功能,然而它們並沒有直接的關係,且互相獨立

class Dog:
def talk(self):
print("汪汪汪")

class Cat:
def talk(self):
print('喵喵!')

class Pig:
def talk(self):
print("哼哼哼!")