zoukankan      html  css  js  c++  java
  • 类的多态

    #我们前面了解了继承,继承可以帮助我们重复使用代码。但对于继承中的示例,无论是Dog还是Cat,调用父类的run()方法时显示的都是Animal is running.,如果想让结果显示为Dog is running.和Cat is running.,该如果处理呢?
    #我们对Dog和Cat做如下改进:
     1 #! /usr/bin/python3
     2 #-*-coding:UTF-8-*-
     3 #clas_多态
     4 
     5 class Animal(object):
     6     def run(self):
     7         print('Animal is running.')
     8 
     9 class Dog(Animal):
    10     def run(self):
    11         print('Dog is running.')
    12 
    13 class Cat(Animal):
    14     def run(self):
    15         print('Cat is running.')
    #执行如下语句:
    1 dog=Dog()
    2 print('实例化Dog类')
    3 dog.run()
    4 
    5 cat=Cat()
    6 print('实例化Cat类')
    7 cat.run()
    #程序执行结果如下:
    1 D:Pythonworkspacedatatime20171129>python class_多态.py
    2 实例化Dog类
    3 Dog is running.
    4 实例化Cat类
    5 Cat is running.
    #由执行结果看到,分别得到了Dog和Cat各自的running结果。
    #当子类和父类存在相同的run()方法时,子类的run()方法会覆盖父类的run()方法,在代码运行时总会调用子类的run()方法,称之为多态。
    #多态来自于希腊语,意思是有多种形式。多态意味着即使不知道变量所引用的对象类型是什么,也能对对象进行操作,多态会根据对象(或类)的不同而表现出不同的行为。例如,我们在上面的Animal类中定义了run方法,Dog和Cat分别继承Animal类,并且分别定义了自己的run方法,最后Dog和Cat调用的还是自己定义的run方法。
    #为了更好了解什么是多态,我们对数据类型再做一个说明。当我们定义一个类时,实际上就是定义了一种数据类型。定义的数据类型和Python自带的数据类型(如str、list、dict)没什么区别。
     1 #! /usr/bin/python3
     2 #-*-coding:UTF-8-*-
     3 #clas_多态
     4 
     5 class Animal(object):
     6     def run(self):
     7         print('Animal is running.')
     8 
     9 class Dog(Animal):
    10     pass
    11 
    12 a=list()           #a是list类型
    13 b=Animal()         #b是Animal类型
    14 c=Dog()            #c是Dog类型
    #下面用isinstance()方法判断一个变量是否是某个类型。
    1 print('a是否是list类型:',isinstance(a,list))
    2 print('b是否是Animal类型:',isinstance(b,Animal))
    3 print('c是否是Dog类型:',isinstance(c,Dog))
    #执行结果如下:
    1 D:Pythonworkspacedatatime20171129>python class_多态.py
    2 a是否是list类型: True
    3 b是否是Animal类型: True
    4 c是否是Dog类型: True
    #由执行结果看到,a,b,c确实分别为list、Animal、Dog三种类型。我们再执行如下语句:
    1 print('c是否是Dog类型:',isinstance(c,Dog))
    2 print('c是否是Animal类型:',isinstance(c,Animal))
    #执行结果如下:
    1 c是否是Dog类型: True
    2 c是否是Animal类型: True
    #由执行结果看到,c既是Dog类型又是Animal类型,这怎么理解呢?
    #因为Dog是从Animal继承下来的,当我们创建Dog的实例c时,我们认为c的数据类型是Dog,但c同时也是Animal,Dog本来就是Animal的一种。
    #在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以看作是父类。但反过来就不行,例如如下语句:
    1 print('b是否是Dog类型:',isinstance(b,Dog))
    #执行结果如下:
    1 b是否是Dog类型: False
    #由输出结果看到,变量b是Animal的实例化对象,是Animal类型,但不是Dog类型,也就是Dog可以看成Animal,但Animal不可以看成Dog。
    #我们再看一个示例。编写一个函数,这个函数接收一个Animal类型的变量,定义并执行如下函数,执行时传入Animal的实例:
     1 #! /usr/bin/python3
     2 #-*-coding:UTF-8-*-
     3 #class_多态_2
     4 
     5 class Animal(object):
     6     def run(self):
     7         print('Animal is running.')
     8 
     9 def run_two_times(animal):
    10         animal.run()
    11         animal.run()
    12 
    13 run_two_times(Animal())
    #执行结果如下:
    1 D:Pythonworkspacedatatime20171129>python class_多态_2.py
    2 Animal is running.
    3 Animal is running.
    #若执行函数传入Dog的实例,操作如下:
     1 #! /usr/bin/python3
     2 #-*-coding:UTF-8-*-
     3 #class_多态_2
     4 
     5 class Animal(object):
     6     def run(self):
     7         print('Animal is running.')
     8 
     9 class Dog(Animal):
    10     def run(slef):
    11         print('Dog is running.')
    12 
    13 def run_two_times(animal):
    14         animal.run()
    15         animal.run()
    16 
    17 run_two_times(Dog())
    #得到的执行结果如下:
    1 D:Pythonworkspacedatatime20171129>python class_多态_2.py
    2 Dog is running.
    3 Dog is running.
    #若传入Cat的实例,操作如下:
     1 #! /usr/bin/python3
     2 #-*-coding:UTF-8-*-
     3 #class_多态_2
     4 
     5 class Animal(object):
     6     def run(self):
     7         print('Animal is running.')
     8 
     9 class Dog(Animal):
    10     def run(slef):
    11         print('Dog is running.')
    12 
    13 class Cat(Animal):
    14     def run(self):
    15         print('Cat is running.')
    16 
    17 def run_two_times(animal):
    18         animal.run()
    19         animal.run()
    20 
    21 run_two_times(Animal())
    22 run_two_times(Dog())
    23 run_two_times(Cat())
    #得到执行结果如下:
    1 D:Pythonworkspacedatatime20171129>python class_多态_2.py
    2 Animal is running.
    3 Animal is running.
    4 Dog is running.
    5 Dog is running.
    6 Cat is running.
    7 Cat is running.
    #看上去没有什么特殊的地方,已经正确输出预期结果了,但仔细想想看,如果再定义一个Bird类型,也继承Animal类,定义如下:
     1 #! /usr/bin/python3
     2 #-*-coding:UTF-8-*-
     3 #class_多态_2
     4 
     5 class Animal(object):
     6     def run(self):
     7         print('Animal is running.')
     8 
     9 class Dog(Animal):
    10     def run(slef):
    11         print('Dog is running.')
    12 
    13 class Cat(Animal):
    14     def run(self):
    15         print('Cat is running.')
    16 
    17 class Bird(Animal):
    18     def run(self):
    19         print('Bird if flying the sky.')
    20 
    21 def run_two_times(animal):
    22         animal.run()
    23         animal.run()
    24 
    25 run_two_times(Animal())
    26 run_two_times(Dog())
    27 run_two_times(Cat())
    28 run_two_times(Bird())
    #程序执行结果如下:
    1 D:Pythonworkspacedatatime20171129>python class_多态_2.py
    2 Animal is running.
    3 Animal is running.
    4 Dog is running.
    5 Dog is running.
    6 Cat is running.
    7 Cat is running.
    8 Bird if flying the sky.
    9 Bird if flying the sky.
    #由执行结果看到,新增的Animal子类不必对run_two_times()方法做任何修改。实际上,任何依赖Animal作为参数的函数或方法都可以不加修改地正常运行,原因就在于多态。
    #多态的好处是:当我们需要传入Dog、Cat、Bird等对象时,只需要接收Animal类型就可以了,因为Dog、Cat、Bird等都是Animal类型,按照Animal类型进行操作即可。由于Animal类型有run()方法,因此传入的类型只要是Animal类或继承自Animal类,都会自动调用实际类型的run()方法。
    #多态的意思是:对于一个变量,我们只需要知道它是Animal类型,无需确切知道它的子类型,就可以放心调用run()方法。具体调用的run()方法作用于Anial、Dog、Cat或Bird对象,由运行该对象的确切类型决定。
    #多态真正的威力在于:调用方只管调用,不管细节。当我们新增一种Animal的子类时,只要确保run()方法编写正确即可,不用管原来的代码如何调用的,这就是著名的“开闭”原则:对于扩展开放,允许新增Animal子类;对于修改封闭,不需要修改依赖Animal类型的run_two_times()等函数。
    #很多函数和运算符都是多态的,也许你写的程序也可能时,即使你并非有意这样的。只要使用多态函数和运算符,多态就会消除。唯一能够毁掉多态的是使用函数显式地检查类型,如type、isinstance函数等,如果有可能,就尽量避免使用这些会毁掉多态的方式,重要的是如何让对象按照我们希望的方式工作,无论它是否是正确类型或类。
  • 相关阅读:
    用例要素(非原创)
    边界接口设计
    项目管理平台架构
    内外网邮件自动转发
    Python技术公众号100天了
    将博客搬至CSDN
    Android项目真的要去做混淆(加密)处理
    【转】Android Gson的使用
    【转】在eclipse上使用Git
    在AChartEngine上绘图,手指标记当前位置
  • 原文地址:https://www.cnblogs.com/DLHe/p/7927394.html
Copyright © 2011-2022 走看看