多态

多态

一、什么是多态性

多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

  1. 序列数据类型有多种形态:字符串,列表,元组
  2. 动物有多种形态:人,狗,猪

注意:多态与多态性是两种概念

多态性是指具有不同功能的函数可以使用相同的函数名这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

#多态基础
class Animal:
    def speak(self):
        pass

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

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

class People(Animal):
    def speak(self):
        print('say hello')

pig=Pig()
dog=Dog()
people=People()
pig.speak()
dog.speak()
people.speak()

# 实现多态
def animal_speak(obj):
    obj.speak()
animal_speak(pig)
animal_speak(people)

哼哼哼
汪汪
say hello
哼哼哼
say hello

二、多态的使用

2.1文件形态多态性的使用

# 文件有多种形态:文件、文本文件、可执行文件
import abc


class File(metaclass=abc.ABCMeta):  # 同一类事物:文件
    @abc.abstractmethod
    def click(self):
        pass


class Text(File):  # 文件的形态之一:文本文件
    def click(self):
        print('open file')


class ExeFile(File):  # 文件的形态之二:可执行文件
    def click(self):
        print('execute file')


text = Text()
exe_file = ExeFile()

text.click()
exe_file.click()
def func(obj):
    obj.click()


func(text)
func(exe_file)

2.2 序列数据类型多态性的使用

def func(obj):
    print(len(obj))


func('hello')
func([1, 2, 3])
func((1, 2, 3))

5
3
3

综上可以说,多态性是一个接口(函数func)的多种实现(如obj.run(),obj.talk(),obj.click(),len(obj))

三、使用abc实现接口(不常用)

# 第一种方式:用abc实现接口统一化, 约束代码(用的比较少)
import abc
# 第一个在括号中写metaclass = abc.ABCMeta
class Animal(metaclass=abc.ABCMeta):
    # 第二要在约束的方法上,写abc.abstractethod装饰器
    @abc.abstractmethod
    def speak(self):
        pass

class Pig(Animal):
    def speak(self):
        print("猪猪")

class Dog(Animal):
    def speak(self):
        print("旺旺")

def animal_speak(obj):
    obj.speak()

# 如果继承类中,子类中没有定义speak函数则会报错
pig = Pig()
dog = Dog()
animal_speak(pig)
animal_speak(dog)

三、使用异常处理来实现(常用)

class Animal():
    def speak(self):
        #主动抛出异常
        raise Exception('你得给我重写它啊')
class Pig(Animal):
    def speak(self):
        print('哼哼哼')
class People(Animal):
    def speak(self):
        print('say hello')
pig=Pig()
pe=People()
def animal_speak(obj):
    obj.speak()

# 使用异常实现接口,如果子类中没有定义speak函数,则会调用父类,从而报错
animal_speak(pig)
animal_speak(pe)

四、常用定义接口方式

 Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’

python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象

也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

#二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass

其实大家一直在享受着多态性带来的好处,比如Python的序列类型有多种形态:字符串,列表,元组,多态性体现如下

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

#我们可以在不考虑三者类型的前提下使用s,l,t
s.__len__()
l.__len__()
t.__len__()

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

五、多态的好处

其实大家从上面多态性的例子可以看出,我们并没有增加新的知识,也就是说Python本身就是支持多态性的,这么做的好处是什么呢?

  1. 增加了程序的灵活性:以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
  2. 增加了程序额可扩展性:通过继承Animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
class Cat(Animal):  # 属于动物的另外一种形态:猫
    def talk(self):
        print('say miao')


def func(animal):  # 对于使用者来说,自己的代码根本无需改动
    animal.talk()


cat1 = Cat()  # 实例出一只猫
func(cat1)  # 甚至连调用方式也无需改变,就能调用猫的talk功能
  • 上述代码我们新增了一个形态Cat,由Cat类产生的实例cat1,使用者可以在完全不需要修改自己代码的情况下。使用和人、狗、猪一样的方式调用cat1的talk方法,即func(cat1)

六、总结

  1. 多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度);
  2. 多态性:一种调用方式,不同的执行效果(多态性);
  3. 接口:一般通过异常实现;
  4. 鸭子类型:看起来像鸭子
posted @ 2019-08-28 22:39  RandySun  阅读(196)  评论(0编辑  收藏  举报