首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Py测开《多态和鸭子类型的区别》

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

作者头像
清菡
发布2022-04-27 19:25:19
4550
发布2022-04-27 19:25:19
举报
文章被收录于专栏:清菡软件测试清菡软件测试

目录

  • 一、面向对象编程的三大特征
  • 二、什么是多态
  • 三、实现多态的步骤
    • 1.Python中函数的参数是没有类型限制的
    • 2.子类的对象是不是属于这个父类
    • 3.实现伪多态
  • 四、多态的意义
  • 五、鸭子类型
    • 1.鸭子类型的体现
    • 2.代码实现鸭子类型

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

封装,继承,多态。

  • 封装:将数据和方法放在一个类中就构成了封装。
  • 继承:Python中的一个类可以继承一个类也可以继承多个类,被继承的类叫父类(或者叫基类,base class ),继承的类叫子类。
  • 多态(Polymorphism):指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同的子类对象调用相同的方法,产生不同的执行结果,多态可以增加代码的灵活度。

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

二、什么是多态

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

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

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

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

都是动物类,但是有不同的形态

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

三、实现多态的步骤

  • 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])

运行结果

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是不是属于父类的类型?

运行结果

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

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])

运行结果

这个就是个多态。一类事物有不同的形态。传进去的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])

运行结果

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

四、多态的意义

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

  • 对于一个变量,我们只需要知道它是Base类型,无需确切地知道它的子类型,就可以放心地调用run()方法,(调用方只管调用,不管细节)。
  • 当需要新增功能,只需要新增一个Base的子类实现run()方法,就可以在原来的基础上进行功能扩展,这就是著名的“开放封闭”原则:
    • 对扩展开放:允许新增Base子类。
    • 对修改封闭:不需要修改依赖Base类型的run()等函数。

五、鸭子类型

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

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])

运行结果

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

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

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

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

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

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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-04-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 清菡软件测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 目录
    • 一、面向对象编程的三大特征
      • 二、什么是多态
        • 三、实现多态的步骤
          • 1.Python中函数的参数是没有类型限制的
          • 2.子类的对象是不是属于这个父类?
          • 3.实现伪多态
        • 四、多态的意义
          • 五、鸭子类型
            • 1.鸭子类型的体现
            • 2.代码实现鸭子类型
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档