类的多态

#我们前面了解了继承,继承可以帮助我们重复使用代码。但对于继承中的示例,无论是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函数等,如果有可能,就尽量避免使用这些会毁掉多态的方式,重要的是如何让对象按照我们希望的方式工作,无论它是否是正确类型或类。
原文地址:https://www.cnblogs.com/DLHe/p/7927394.html