多 态

多 态

函数(方法)多态

在类的继承的例子中,我们看到,在父类和子类中都有一个函数fight(),那么在子类对象调用时究竟调用哪一个呢?Python和很多面向对象语言一样,采用的是就近原则,先看自己有没有这个函数定义,如果有,就优先采用自己的。这和我们日常生活中的一些事情也非常契合,如找一本书来看,一般来说我们会选择自己爱看的那本书。

那么问题来了,这样的方式究竟有什么好处呢?在调用时,既然已经和对象绑定,自然是调用自己的函数,除了不用写多个函数名之外,似乎也没有简化多少代码。

我们换一个场景来看待这个问题。假设我们在游戏中,需要观察每个武将或者士兵战斗的情况。注意,此时是从外界的角度来看待这个问题,假设我们要把这个观察过程写成一个名为Warshow()的函数,需要输入参数(需要观察的对象)才可以进行观察。在设计Warshow()函数时Para应该输入什么参数呢?

小P 问一问

在设计Warshow()函数时Para 应该输入什么参数呢?

输入步兵参数?

输入武将参数?

如果还有骑兵,需要输入骑兵参数吗?

如果不指定参数类型,可以吗?如果没有多态机制,必须要进行指定,否则它们都有fight()函数,究竟调用哪一个呢?

但是有了多态机制就好办了。不管是步兵类、武将类、骑兵类,如果把它们都放在Person类之下(成为其子类),那么这个Para参数的类型直接定义为Person类即可。这样就实现了一个接口、多种形态。下面我们来看一个完整的例子:

输出结果为:

在这个例子中,Warshow()函数的参数类型仅仅设计为Person类,但是在使用中可以输入Wujiang类的对象GY和Bubing类的对象Soldier1,并且在最后的执行过程中,它们可以分别调用各自的fight()函数。

运算符重载

以上是方法的多态,还有一种多态是运算符的多态,即运算符重载。例如,加法运算符“+”一般对整数、浮点数进行操作,如果是两个向量相加,就没有相应的加法运算符与之对应,这时可以自行设计。

例如,有两个向量vec1和vec2,坐标分别为(2,4)和(3,-2),它们相加后的向量sumofvec的坐标为(5,2),如图5-4所示。

图5-4 向量相加

Python同样支持运算符重载,实例如下。

这里采用对__add__()函数的重新定义完成运算符“+”的重载。

以上代码执行结果如下:

在这里,我们对__add__()进行了重新定义,实际上就是对加法运算符进行了重新定义,从而实现了对向量的相加。