类的多态与鸭子类型

类的多态与鸭子类型

一、什么是多态?

  • 多态是同一类事物具有的多种形态。

我国有句俗语:“龙生九子,各有不同”。这就是多态。多态是面向对象编程的重要特点之一。

  • 示例:

    #多态:同一类事物有多种形
    class People:
        pass
    
    class me(People):
        pass
    
    class sister(People):
        pass
    
    class brother(People):
        pass
    

    你、你的姐姐、你的兄弟,都属于人这同一类。这就是多态。

二、由多态带来的特性=》多态性

1.什么是多态性

  • 多态性指的是在不考虑对象的具体类型下, 直接使用对象的方法, 同一种调用方式, 运行的效果不一样 (这就需要在设计时, 把对象的调用方法设计成形式统一的一种)

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

2.多态性的使用

lass Animal:  # 统一所有子类的方法
    def say(self):
        print("动物的基本发声频率: ", end='')

class People(Animal):
    def say(self):
        super().say()
        print("呼呼呼哈哈哈")

class Pig(Animal):
    def say(self):
        super(Pig, self).say()
        print("哼哼哼哈哈哈")

class Dog(Animal):
    def say(self):
        super(Dog, self).say()
        print("汪汪汪哈哈哈")

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

# obj1.say()
# obj2.say()
# obj3.say()

#我们不考虑这“obj1、obj2、ogj3”三个对象是什么类型,他们都有"say"方法
# 定义统一的接口, 接受传入的都属于动物的对象
def animal_say(obj):
    obj.say()

animal_say(obj1)
animal_say(obj2)
animal_say(obj3)

3.多态性的好处

  • 由多态性的关系, 对象的调用方式可以更进一步, 可以定义一个统一的接口来使用,从而增强了程序的灵活性和可扩展性.

  • 增加了程序的灵活性 : 对于使用者来说都是使用同一种方式去调用每个对象的方法

  • 增加了程序的可扩展性 : 如果我们新建一个类或者又实例出一个对象, 使用者无需更改自己的代码, 还是原来的调用方式

    class Animal:  # 统一所有子类的方法
        def say(self):
            print("动物的基本发声频率: ", end='')
    
    class People(Animal):
        def say(self):
            super().say()
            print("呼呼呼哈哈哈")
    
    class Pig(Animal):
        def say(self):
            super(Pig, self).say()
            print("哼哼哼哈哈哈")
    
    class Dog(Animal):
        def say(self):
            super(Dog, self).say()
            print("汪汪汪哈哈哈")
    #新增一个“鸭”类
    class Duck(Animal):
        def say(self):
            super(Duck,self).say()
            print("嘎嘎嘎哈哈哈")
    
    obj1 = People()
    obj2 = Pig()
    obj3 = Dog()
    obj4=Duck()
    
    # 对于使用者来说代码不需要改变
    def animal_say(obj):
        obj.say()
    animal_say(obj1)
    animal_say(obj2)
    animal_say(obj3)
    
    # 还是使用相同的调用方式
    animal_say(obj4)
    # 这样我们就新增了一个"Duck"形态, 产生了一个"obj4"实例, 使用者可以在完全不需要修改自己代码的情况下,使用之前一样的调用方式来调用"obj4"的"say"方法
    
    
列举python中含有这种多态性的思想的实例
"""
1. 字符串, 列表, 元组, 字典, 集合等等都可以直接使用len()函数, 完美的展现了多态性的思想. 它们虽然都不是同一类型, 但是它们都是多个值的类型. 所以我们都可以不考虑它们的对象的具体类型直接使用对象.
2. python中的len()函数, 内部就是对__len__()的调用的封装. 
"""
str1 = 'hello'
list1 = [1, 2, 3]
tuple1 = (1, 2, 3)
dict1 = {'name': 'egon', 'age': 81}
set1 = {'a', 'b', 'c'}
# 基于多态性可以不考虑对象的类型直接使用对象
print(str1.__len__())
print(list1.__len__())
print(tuple1.__len__())
print(dict1.__len__())
print(set1.__len__())

# 使用提供好的统一的接口
print(len(str1))
print(len(list1))
print(len(tuple1))
print(len(dict1))
print(len(set1))

# 自定义接口
def my_len(obj):
    return obj.__len__()

print(my_len(str1))
print(my_len(list1))
print(my_len(tuple1))
print(my_len(dict1))
print(my_len(set1))

三、abs 模块限制子类必须重写父类的某些方法

多态的前提是 : 同一类事物, 最好的方法就是让他们继承同一个基类

为了保证多态, 我们可以使用 abc 模块来强制的要求子类必须重写父类的某些功能, 如果不重写, 则会报错

多态性的本质在于不同的类中定义有相同的方法名, 这样我们就可以不考虑类而统一用一种方式去适用对象, 基于这种前提下, 我们还可以进一步使用限制性的思想来提升这种高度. 因此我们可以通过在父类中引入抽象类的概念来硬性限制子类必须有某些方法名

import abc

class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod  # @abc.abstractmethod装饰器后严格控制子类必须实现这个方法, 才能正常的实例化
    def say(self):  # 注意1: 引入抽象类概念的类只需要定义一个标准,不写代码硬性规定继承它的子类必须遵循它的标准
        pass

# obj = Animal()  # 注意2: 不能实例化引入抽象类概念的类. 抛出异常: TypeError: Can't instantiate abstract class Animal with abstract methods say

class People(Animal):
    def say(self):
        pass

class Dog(Animal):
    def say(self):
        pass

class Pig(Animal):
    def say(self):
        pass

# 注意3: 继承引入抽象类概念的类, 其子类必须含有定义抽象类中的方法, 才能正常的实例化.
obj1 = People()
obj2 = Dog()
obj3 = Pig()

abs 模块使用小结

  • abs 模块不是我们来保证多态的惯用做法, Python中有其他方法可以实现
  • python中不推荐强制使用父类来约束子类,python推崇使用鸭子类型来实现多态

四、鸭子类型

1.什么是鸭子类型

  • 鸭子类型, 它并不要求严格的继承体系,即一个对象看起来像鸭子, 走路像鸭子, 说话也像鸭子, 具备了鸭子的所有特征和行为, 那么我们就可以说这个对象就是的鸭子
  • 注意:在鸭子类型中,关注点在于对象的行为,能做什么;而不是关注对象所属的类型。

2.为什么推崇鸭子类型?

  • 其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,这正是Python崇尚的“鸭子类型”(duck typing)
  • 比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度

3.鸭子类型的示例

class Cpu:
    def read(self):
        print("Cpu read")

    def write(self):
        print("Cpu write")

class Mem:  # Mem 显示随机存取存贮器的分配信息
    def read(self):
        print("Mem read")
        
    def write(self):
        print("Mem write")

class Txt:
    def read(self):
        print("Txt read")

    def write(self):
        print("Txt write")
        
obj1 = Cpu()
obj2 = Mem()
obj3 = Txt()

# 制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象
obj1.read()
obj1.write()

obj2.read()
obj2.write()

obj3.read()
obj3.write()

ps : Python, Go 语言中实现多态可以不需要继承父类, 而其他语言总需要(例:Java)

参考资料

https://www.liaoxuefeng.com/wiki/1016959663602400/1017497232674368

https://www.cnblogs.com/guolei2570/p/8830934.html

https://www.jianshu.com/p/e97044a8169a

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贾维斯Echo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值