妻子:你看看你,整天好吃懒做。儿子长大了要是像你,就完了。丈夫:像我?哼!要是不像我,你就完了!

python中的继承与方法重写

在生活中,我们通常会遇到一些事物,它们是基于另外一些事物改造过来的。二者有共同的地方,新事物又增加了自己的特性。python中,用继承来描述这样的事情。假设有一个Person类,又有一个Student类,Student是在Person类基础上扩展而来的,如下:

python 多继承 怎么传参 python多继承的顺序_多继承

类的继承

第14行展示了类的继承方式,即在定义类时,在括号中添加其父类。

第24行,Student类中的hello方法,使用了在父类中定义的name和age,并且是以self为前缀的。这说明,子类可以使用在父类中定义的类变量和方法。这正是继承的核心意义。

上面的demo中,还展示了方法的重写。我们知道,在python中,万物皆对象,所以,无论是类变量还是方法,本质都是一个标识符指向了一个对象。当标识符相同时,后声明的会覆盖先声明的。对于继承来说,当A类继承了B类时,就相当于拥有了B类中的类变量和方法。所以,当在A类中定义一个和B类中原有同名的变量或方法时,会覆盖掉B类中原有的。方法的覆盖,在类的继承中,就称为方法重写。

普通方法可以重写,如上面的hello,构造方法也可以重写,如上面的__init__。上面的demo中,Person和Student都有自己的构造方法,所以,在实例化时,需要按照自己的构造方法的要求,提供相应的参数,如下:

python 多继承 怎么传参 python多继承的顺序_python 多继承 怎么传参_02

对象创建

如上所示,创建Person对象需要提供两个参数,name和age,创建Student时,则需要提供三个参数,name、age和grade。

接下来,在30和31行,分别调用了Person和Student的hello方法。假设之类没有重写hello方法,student.hello()则会调用到Person中的hello方法。

python中,定义类时,如果不提供__init__方法,会自动生成一个无参构造方法。但是,当存在继承关系时,子类会从其父类继承__init__方法,所以,如果在案例中,Student不提供__init__方法,在实例化时,也必须提供name和age两个参数,因为这是在Person中的__init__方法限定的。

有时候,我们希望在子类中去调用父类的方法,可以以父类名作为前缀。如下:

python 多继承 怎么传参 python多继承的顺序_父类_03

调用父类方法

注意19行和24行被注释掉的部分,这也是一种调用父类方法的形式,super后面的括号中跟子类名和子类对象,调用方法时,不再传入self。这种方法,是不推荐的。一是因为写法复杂,二是因为在多继承的情况下,会不可用。

综合以上,得出子类和父类的三点关于方法的关系:

1. 子类可继承父类中的方法。

2. 子类可重写父类中的方法。

3. 子类可调用父类中的方法。

python中的链式继承和多继承

修改前面的案例,再创建一个Biology类,包含一个run方法,并使Person继承Biololgy。如下:

python 多继承 怎么传参 python多继承的顺序_python多继承执行顺序_04

链式继承

这种情况下,通过Student类的实例,也可以调用到run方法,这说明,当存在链式继承关系时,一个类会继承其所以祖先类的类变量或方法。

有过其他语言基础的同学,如Java,应该会知道,在Java中,一个类只能有一个父类,是不允许多继承的,但是在python中,是允许多继承的,写法是都写入类名后的括号中,以逗号隔开。如下:

python 多继承 怎么传参 python多继承的顺序_多继承_05

多继承

多继承和链式继承,对于Student类来说,事实上效果是差不多的,即Student都得到了Biology和Person中的类变量和方法。不同点在于,在多继承的情况下,如果把Person和Biology的继承关系去掉,对于Student没有影响,但是Person和Biology之间将不存在继承关系。

接下来,我们来考察一下在链式继承和多继承的情况下,类变量和方法的覆盖问题。

链式继承的情况下,假设有A类继承于B类,B类又继承于C类,在B类和C类中,都包含有run方法,那么,当A类的实例化对象调用run时,会调用到B类的run。这是很显然的。因为B类是A类的直接父类。B类已经重写了C类的run方法。所以,C类的run方法对于A类说,可以理解为是已经不存在或不可见的。

多继承的情况下,假设有A类继承于B和C类。那么,run方法的执行情况,会和继承的书写顺序相关。python会按照书写顺序,从前向后依次查找,也就是说,B类写在前面,就执行B类的,C类写在前面,就执行C类的。

有同学可能会想到一种比较复杂的情况:假设A多继承于B和C,B在C前。而B类又继承于C。会怎样呢?如下:

python 多继承 怎么传参 python多继承的顺序_多继承_06

链式继承和多继承共存

事实上,这种写法是不允许的。在A类的继承关系中,你可以只写B,不写C。如果你一定要写,由于C是B的父类,那么,C就必须写在B的前面,否则会报TypeError,类型错误。

所以,我们在类定义时,一定要做充分的思考,将类的继承关系考虑清楚。尽量避免链式继承和多继承混合使用的情形。