Py测开《多态和鸭子类型的区别》

目录

  • 一、面向对象编程的三大特征

  • 二、什么是多态

  • 三、实现多态的步骤

    • 1.Python中函数的参数是没有类型限制的

    • 2.子类的对象是不是属于这个父类

    • 3.实现伪多态

  • 四、多态的意义

  • 五、鸭子类型

    • 1.鸭子类型的体现

    • 2.代码实现鸭子类型

一、面向对象编程的三大特征

封装,继承,多态。

  • 封装:将数据和方法放在一个类中就构成了封装。

  • 继承:Python中的一个类可以继承一个类也可以继承多个类,被继承的类叫父类(或者叫基类,base class ),继承的类叫子类。

  • 多态(Polymorphism):指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度。

定义一个类,它就是封装。通过类,可以将类里面的一些属性和方法封装在一起。子类继承父类,可以获得父类里面的属性和方法,这个就叫做继承。

二、什么是多态

严格来说,Python中是没有多态的,但是Python中可以实现伪多态,Python中函数的参数是没有类型限制的。Python中有个鸭子类型,比多态更厉害。

多态是建立在继承的基础上的。指的是一类事物有多种形态,其实就是一个父类有多个子类。

父类里面有某个方法,在子类中同样也有这个方法。但是在子类中有这个方法体现的形式和父类中不一样。

在调用这个父类,它所有的子类对象里面,同样是调用同一个方法。因为是不同的子类,所以执行的内容、结果、功能不一样,这就是多态。

5072ba14c453b21e93c8d7d9ae479564.png
都是动物类,但是有不同的形态

多态是建立在继承的基础上的。

三、实现多态的步骤

  • 1.定义一个父类(Base),实现某个方法(比如:run)。

  • 2.定义多个子类,在子类中重写父类的方法(run),每个子类run方法实现不同的功能。

  • 3.假设我们定义了一个函数,需要一个Base类型的对象的参数,那么调用函数的时候,传入Base类不同的子类对象,那么这个函数就会执行不同的功能,这就是多态的体现。

Python中实现的多态是伪多态。Python中定义一个函数,只要函数给它传参数,对于函数的参数是没有类型限制的。

c和java定义一个函数,函数的参数是有类型限制的。指定这个函数的参数只能传什么类型。

1.Python中函数的参数是没有类型限制的

定义一个函数,调用的时候可以传字符、数值、列表。a这个参数没类型限制,传个类进去也行,传个函数进去也可以,传个对象进去也可以,传什么都可以,没有类型限制。

#Python中函数的参数是没有类型限制的。
def func(a):
    print(a)


func(122)
func('1213')
func([12,22])
4fad8b61113da3efbf3afdb509227ca8.png
运行结果

2.子类的对象是不是属于这个父类?

假如Python是个强类型语言。函数只能传父类(Base)这个类型的数据。接下来子类的对象是不是属于这个父类?

# 伪多态的实现。
class Base(object):
    def run(self):
        print("__base___run___:慢慢走路")

class Cat(Base):#继承Base。
    def run(self):#同样里面也有run()方法。
        print("___cat___run___:会爬树")

class Dog(Base):
    def run(self):
        print("___dog___run___:跑得特别快")

b_obj=Base()
c_obj=Cat()
d_obj=Dog()
print(isinstance(c_obj,Base))

多态是建立在继承的基础上,同样多态要重写。

子类的对象c_obj是不是属于父类的类型?
40be4576c7993fa17f6668485606658f.png
运行结果

子类所创建出来的对象也属于父类的类型。

3.实现伪多态

假设func()的参数需要Base类型的。Cat和Dog这个子类创建出来的对象也是属于Base类型的。

class Base(object):
    def run(self):
        print("__base___run___:慢慢走路")

class Cat(Base):
    def run(self):
        print("___cat___run___:会爬树")

class Dog(Base):
    def run(self):
        print("___dog___run___:跑得特别快")

class Pig(Base):#同样也继承于Base
    pass#这个里面没有任何方法。

b_obj=Base()
c_obj=Cat()
d_obj=Dog()
p_obj=Pig()

# 子类的对象是属于父类的类型。
# print(isinstance(c_obj,Cat))
# print(isinstance(c_obj,Base))

#Python中函数的参数是没有类型限制的。
# 假设func的参数需要Base类型的。
def func(base_obj):
    base_obj.run()
func(b_obj)
func(c_obj)
func(d_obj)
func(p_obj)#这个类创建出来的对象,它传进去的时候,它里面没有run()方法,调用父类的run方法。



# func(122)
# func('1213')
# func([12,22])
b955fe1795756e0ebef347d2fd694f6f.png
运行结果

这个就是个多态。一类事物有不同的形态。传进去的b_obj、c_obj、d_obj、p_obj都是属于Base这个类型的。

Base这个父类有很多个子类。参数限定的时候,限定的是Base这个类。

但是如果传入不同子类,同样的方法传入这个类型的对象。因为是不同的子类创建出来的,它会执行不同的功能。

有一个不同的体现,那么这种就叫做多态。

注意:Python中函数的参数是没有类型限制的,所以多态在Python中的体现并不是很严谨。多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。

不修改原来已经实现的功能代码,通过继承扩展新的功能:

不修要修改原来已经实现的功能代码,通过继承扩展新的功能。重新定义方法,变成另外一种形态:

# 伪多态的实现。
class Base(object):
    def run(self):
        print("__base___run___:慢慢走路")

class Cat(Base):
    def run(self):
        print("___cat___run___:会爬树")

class Dog(Base):
    def run(self):
        print("___dog___run___:跑得特别快")

class Pig(Base):#同样也继承于Base
      def run(self):
          print("这是一个幂运算")

class CCC(Base):
    def run(self):#重新定义方法,变成另外一种形态。
        print("cccc功能")

b_obj=Base()
c_obj=Cat()
d_obj=Dog()
p_obj=Pig()
c=CCC()

# 子类的对象是属于父类的类型。
# print(isinstance(c_obj,Cat))
# print(isinstance(c_obj,Base))

#Python中函数的参数是没有类型限制的。
# 假设func的参数需要Base类型的。
def func(base_obj):
    base_obj.run()
func(b_obj)
func(c_obj)
func(d_obj)
func(p_obj)
func(c)



# func(122)
# func('1213')
# func([12,22])
55f222408198952fc7aff1226f92183a.png
运行结果

在Python里面这个是伪多态的实现。

四、多态的意义

多态的意义:开放封闭的原则。

  • 对于一个变量,我们只需要知道它是Base类型,无需确切地知道它的子类型,就可以放心地调用run()方法,(调用方只管调用,不管细节)。

  • 当需要新增功能,只需要新增一个Base的子类实现run()方法,就可以在原来的基础上进行功能扩展,这就是著名的“开放封闭”原则:

    • 对扩展开放:允许新增Base子类。

    • 对修改封闭:不需要修改依赖Base类型的run()等函数。

五、鸭子类型

鸭子类型概念: 它并不要求严格的继承体系,关注的不是对象的类型本身,而是它是如何使用的,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

81e252011dddde05ea036f253f6b3a6a.png

1.鸭子类型的体现

  • 静态语言:对于静态语言(jave,C#)来讲上面传入的对象必须是Base类型或者它的子类,否则,将无法调用run()方法。

  • 动态语言:对于动态语言Python来讲,上面传入的并不一定要Base类型,也可以是其它类型,只要在内部实现一个run()方法就行了,这就是鸭子类型的体现。

2.代码实现鸭子类型

定义个类不继承Base,在里面定义个run()方法,把MyClass这个类创建个对象。调用这个函数,把m传进去,同样也可以调用。

# 伪多态的实现。
class Base(object):
    def run(self):
        print("__base___run___:慢慢走路")

class Cat(Base):
    def run(self):
        print("___cat___run___:会爬树")

class Dog(Base):
    def run(self):
        print("___dog___run___:跑得特别快")

class Pig(Base):#同样也继承于Base
      def run(self):
          print("这是一个幂运算")

class CCC(Base):
    def run(self):#重新定义方法,变成另外一种形态。
        print("cccc功能")

class MyClass(object):#这个类不继承Base
    def run(self):
        print("是myclass的run方法")

b_obj=Base()
c_obj=Cat()
d_obj=Dog()
p_obj=Pig()
c=CCC()
m=MyClass()

# 子类的对象是属于父类的类型。
# print(isinstance(c_obj,Cat))
# print(isinstance(c_obj,Base))

#Python中函数的参数是没有类型限制的。
# 假设func的参数需要Base类型的。
def func(base_obj):
    base_obj.run()
func(b_obj)
func(c_obj)
func(d_obj)
func(p_obj)
func(c)
func(m)


# func(122)
# func('1213')
# func([12,22])
146d37d5716aa1e5407df732b810a899.png
运行结果

像java和c这种强类型的语言,多态的意义在于参数有类型的限制,限制只能传入某个类型的参数,某个类型对象的数据。那么接下来传数据的话只能传这个类型,或者传它的子类。

在Python里的参数没类型限制的。也就是说不用多态照样能够实现,只要定义一个类,类里面有这个run()方法就行了。

因为传进去的对象在里面调用的是run()方法,自己定义一个类,类里面只要有run()方法,那么就都能够放在这个函数例如func()里面去调用。不会报错,有run()方法就行了。不继承它也可以。这叫做鸭子类型。

自己定义的类里面,只要实现了这个里面的方法:

366db77a3883ee4afeee210cdfbdd56d.png

Python中的多态都是伪多态,因为函数的参数都没类型限制,严格意义来说就没有多态。多态和鸭子类型差不多。Python的鸭子类型开放性更好,只要对象里面实现了某个方法,看起来和它一样可以用就行了。

Python中鸭子类型:新定义一个类,在类里面同样实现这个方法,在方法里面写一些不同的代码,同样是调用这个函数,同样是传一个对象,可以做一些不同的事情。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

清菡软件测试

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

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

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

打赏作者

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

抵扣说明:

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

余额充值