跳转至

多态与多态性

定义

多态指的是同一事物的多种形态.
       水 -- 冰、水蒸气、液态水
       动物 -- 人、狗、猪

多态性:
       继承同一个父类的多个子类, 具有相同的方法名
       在使用的时候, 子类实例化的对象就可以在不用考虑自身具体的数据类型的前提下直接调用功能

多态其实在做规划,统一一个标准...

People、Dog、Pig三个类实例化的peo1、dog1、pig1对象都可以调用父类Animal里的speak()方法. 
当然这三种动物叫的方式不一样...人说话,狗汪汪,猪哼哼.. 三个子类需要分别写一个方法表示叫的方式.
比如, People类派生出talk()方法;Dog类派生出wang()方法;Pig类派生出Hum()方法... 
这样写,有问题吗?没有问题.. 但在调用的时候, 就麻烦啦, 一个叫的功能, 三个子类我要记三个不同的方法名...

若我们将Animal的三个子类派生出的 '表示叫的方式' 的方法名都命名成跟父类一样的speak.
那么但凡需要叫的时候,不用care实例化出来的对象是动物的哪种形态, 只要是动物,都调用speak方法就行啦..


抽象类

硬性强制规定父类建立的标准,子类必须遵循!!若不遵循,子类实例化时就会报错..

父类Animal没有实例化的要求,父类是用来制定标准的, 不能被实例化!!

import abc  # abstractclass 抽象类


# -- 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod  # -- 该装饰器限制子类必须定义有一个名为speak的方法
    def speak():         # -- 抽象方法中无需实现具体的功能
        pass

    @abc.abstractmethod
    def eat():
        pass

class People(Animal):  # -- 但凡继承Animal的子类都必须遵循Animal规定的标准
    def speak(self):
        print('Hello World..')

    def eat(self):
        pass

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

    def eat(self):
        pass

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

    def eat(self):
        pass

# -- 若子类中没有名为speak和eat的方法则会抛出异常TypeError,无法实例化
peo1 = People()  
dog1 = Dog()
pig1 = Pig()

peo1.speak()
dog1.speak()
pig1.speak()

""" 进一步,还可以这样玩!
def my_speak(animal): # 不管具体是哪种动物,只要是动物就行..
    animal.speak()

my_speak(peo1)
my_speak(dog1)
my_speak(pig1)
"""

py中多态性的应用

我们一直在享受着多态性带来的好处, 至今从未停止过.. (⁎⁍̴̛ᴗ⁍̴̛⁎)

# str,list,tuple都是序列类型
s = str('hello')
l = list([1, 2, 3])
t = tuple((4, 5, 6))

# 我们可以在不考虑三者类型的前提下使用s,l,t
# 因为它们都将统计长度的方法 命名为 len()..
s.__len__()
l.__len__()
t.__len__()

len(s)
len(l)
len(t)

鸭子类型

其它语言一提到多态, 就说多态应该在继承的条件下使用.
而python不推崇在继承的背景下实现多态, python推崇的是 鸭子类型. duck typing

[只要你叫的声音像鸭子, 并且你走路的样子也像鸭子, 那你就是鸭子!! 嘎嘎嘎~]

前面我们通过抽象类硬性要求子类怎么样怎么样, python不推崇, 因为提高了耦合度.. Dog、People、Pig类可以不用继承Animal类, 它们三个相互约定, 将叫的方式都命名为speak(). 也能达到多态的效果.

归一化 的思想, 也实现了代码的解耦合... (类是独立的一块一块的 彼此之间不影响)

重要是将标准统一!大家都遵守!!这样可以降低使用的难度, 学习调用的成本..