面向对象编程的一个显著优势就是代码复用,继承就是实现代码复用的一种方式。所谓的继承是指创建一个类时,并不是从零开始构建,而是在一个已有类的基础上进行扩展,可以大大降低工作量。例如:已经定义了一个动物类,对动物共同的属性和行为进行了抽象,现在需要定义一个狗类,而我们知道狗是一种动物,动物拥有的属性和行为狗都拥有,此外狗还有一些特殊的属性和行为,此时,我们可以让狗类继承动物类,然后只需要添加一些狗所特有的属性和方法即可。

在Python中,新建的类可以继承一个或多个父类,父类又可称为基类超类,新建的类称为派生类子类。定义类时,如果没有指定父类,则默认的父类为object,object类是所有类的直接父类或间接祖先类。子类可以继承父类的公有成员,但不能继承其私有成员。如果需要在子类中调用父类的方法,可以使用“super().方法名() ” 或者通过“基类名.方法名()”的方式来实现。Python中类的继承语法如下:

class 子类名(父类1, 父类2, ...., 父类n):

类体

注意圆括号中父类的顺序,使用类的实例对象调用一个方法时,若在子类中未找到,则会从左到右查找父类中是否包含该方法。当没有指定父类时,可以省略一对圆括号。通过类提供的__bases__ 属性可以查看该类的所有直接父类。

object类

object类是Python中所有类的基类。object类中定义了所有类都拥有的一些属性和方法,object类中大部分方法名都是以两个下划线开始、以两个下划线结束,其中比较重要的方法有__new__()__init_()__str__() __eq__() __dir__()等。

__str__() 方法返回一个描述该对象的字符串。当我们通过print()方法打印一个对象时,默认会调用该方法。默认情况下,它返回一个由该对象所属的类名以及该对象十六进制形式的内存地址组成的字符串,这对用户来说并不友好,一般来说,会重写该方法打印对象的具体信息;

__eq__() 方法用于比较两个对象是否相等,默认是没有实现,可根据业务需求重写该方法。使用“==”判断两个对象是否相等时将会调用该方法,如果没有重写该方法,则判断两个对象是否指向同一引用

__dir__() 方法用于显示对象内部所有的属性名和方法名,包括从父类继承而来的属性和方法。

__dict__ 属性以字典的形式显示对象内部存储的所有属性名和属性值

方法的重写

当父类的方法不能满足子类的要求时,可以在子类中重写父类的方法,也就是在子类中写一个和父类的方法名相同的方法


python 两个list一致_python 两个list一致


多继承时调用顺序

创建子类对象时,将会默认按顺序创建所有父类的对象,即调用父类的__new__() 方法。但并不会调用所有父类的__init__() 方法。

如果子类没有提供自己的 __init__() 方法,将会默认调用第一个父类的 __init__() 方法;如果子类提供了 __init__() 方法,则默认不会调用父类的 __init__() ,此时,父类的成员变量将无法初始化,因此,通常会在子类的 __init__() 方法中,显示调用父类的 __init__() 方法。


python 两个list一致_python 两个list一致_02


对当前类和基类进行搜索以确定方法所在的位置。而搜索的顺序就是所谓的「方法解析顺序」(Method Resolution OrderMRO)。对于只支持单继承的语言来说,MRO 一般比较简单,就是从当前类开始,逐个搜索它的父类;而对于支持多继承的语言来说,MRO 就复杂很多。在Python中提供了__mro__ 属性可查看类的搜索顺序。


python 两个list一致_Python_03


对象拷贝

一个对象的变化也会影响另一对象。如果想将原对象的内容复制一份,可用copy模块的copy函数,如 b = copy.copy(a),此时 a 和 b 对象内容相同,但是引用不同。copy函数是浅拷贝,只拷贝当前对象,不会拷贝对象内部的其他对象。如果要递归拷贝对象中的其他对象,可用copy模块的 deepcopy 进行深拷贝,如 b = copy.deepcopy(a),此时,b 完全拷贝了 a 对象及其子对象,a 和 b是完全独立的。


python 两个list一致_子类_04


python 两个list一致_llist对象两个属性相乘在相加_05


今日练习题


python 两个list一致_父类_06