1. 继承
1. 什么是继承
-
继承:就是新建类的方法,新建的类称之为子类或者派生类,子类继承的类叫做父类,也称之为基类或超类。简单的说:一个类可以得到另一个类名称空间中的属性和方法的这个特性,这种特性就是通过继承来实现的
-
继承的特征:
子类可以继承父类的属性(特征和技能),并且可以派生出自己的属性(特征和技能)
-
在python中,一个子类可以继承多个父类,其它编程语言只能一个子类继承一个父类(面试可能会问)
2. 为什么要继承
- 继承的目的就是为了减少代码冗余(减少重复代码)
3. 怎么继承,如何实现继承
-
首先要确定好谁是子类谁是父类
-
在定义类时,子类 + () ,()内写父类的名字,实现子类继承父类
# 子类B继承父类A class A: pass class B(A): pass print(B.__bases__) #查看B继承的父类们,以元组飞形式打印出各父类 print(B.__bases__[0].__dict__) # 查看B的第一个父类的属性
-
什么是抽象?
抽象指的是抽取相似的部分,称之为抽象. -
继承的关系:
对象是特征与技能的结合体.
类是一系列对象相同的特征与技能的结合体.
继承是一系列类相同的特征与技能的结合体.
4. 继承后,对象的属性的搜索顺序
- 下面的查找中,只要找到了就不会继续找了
- 先从对象的名称空间中查找该属性
- 若对象的名称空间中没有,就会去子类的名称空间中查找
- 若子类中没有,就去父类中查找,并且按照父类的继承顺序查找。
5. 新式类和经典类(面试会问)
- python2 中才会有新式类和经典类之分。
- python3 中所有的类都是新式类
1. 新式类
-
什么是新式类:
继承object的类都称之为新式类
python3 中,子类如果不继承自定义的类,会默认继承object
2. 经典类
-
什么是经典类
在python2 中,凡是没有继承object 的类都是经典类
3. mro() / __class__ / __name__
方法
mro()
方法是属于object类中的方法,在多继承情况下,可以用来查看当前类的继承顺序。他返回的结果是一个元组。注意要索引取值。__class__
是对象的方法,可以获得实例化该对象的类。__name__
一种通用的方法,类/函数 通过.__name__
可以获取类/函数的 名字。
4. 钻石继承(也称为菱形继承)
-
在多继承的情况下会形成钻石继承
-
钻石继承的继承顺序:分为 新式类 和 经典类 的继承顺序
(1) 新式类的钻石继承顺序
-
新式类的钻石继承顺序为 : 广度优先。
-
它的特点是按一个子类的继承时括号内的书写顺序,从左到右依次,(如
子类1(A,D,G...)
),先继承:第一个父类A——》A的父类B——》B的父类C——》。。。
第二个父类D——》D的父类E——》E的父类F——》。。。
。。。
但最后继承顶层的父类,再继承object类
(2) 经典类的钻石继承顺序
-
经典类的钻石继承顺序为: 深度优先
-
它的特点是按一个子类的继承时括号内的书写顺序,从左到右依次,(如
子类1(A,D,G...)
),先继承:第一个父类A——》A的父类B——》B的父类C——》。。。——》顶层的父类
第二个父类D——》D的父类E——》E的父类F——》。。。——》顶层父类继承过了,到顶层的父类的最近的一个儿子类就结束继承。开始第三个父类,第三个父类也是同第二个父类一样的继承顺序。
。。。
2. 继承的实例
-
通过继承实现修改json模块的数据类型
import json from datetime import date, datetime print(json.JSONEncoder) print(datetime.today()) # 当前时间 print(date.today()) # 当前日期 # 开发者的角度: 直接转成str # dict1 = { # 'name': 'tank', # 'today': str(datetime.today()), # 'today2': str(date.today()) # } # # res = json.dumps(dict1) # print(res) # isinstance: # python内置的函数,可以传两个参数,判断参数一是否式参数二的一个实例. *********************继承的使用*********************** # 开源者的角度: 修改json源码 class MyJson(json.JSONEncoder): def default(self, o): # 子类派生的功能 # 判断o是否式datetime的一个实例 if isinstance(o, datetime): return o.strftime('%Y-%m-%d %X') elif isinstance(o, date): return o.strftime('%Y-%m-%d') else: # 继承父类的default方法的功能 return super().default(self, o) dict1 = { 'name': 'tank', 'today': datetime.today(), 'today2': date.today() } res = json.dumps(dict1, cls=MyJson) # cls=None,默认指向的是原json的JSONEncoder print(res)
3. 派生
1. 什么是派生
- 派生指的是子类继承父类的属性,并且产生自己新的属性
- 子类派生出新的属性,若与父类的属性相同,则以子类的为准。
2. 子类派生出新的属性,并重用父类的属性
问题:子类继承了父类的__init__
属性,但还需要添加自己的一些新的属性
解决方法:
注意下面的两种方法不要混合使用
-
方法一:
直接通过 父类.__init__(self,要重用的属性) 来实现重用父类属性 class OldboyPeople: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): # 等级, 薪资 def __init__(self, name, age, sex, level, sal): OldboyPeople.__init__(self, name, age, sex) self.level = level self.sal = sal
-
方法二:(比方法一,少写了self)
super是一个特殊的类,在子类中调用super()会得到一个特殊的对象, 通过"."指向的是父类的名称空间. class OldboyPeople: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex class OldboyTeacher(OldboyPeople): # 等级, 薪资 def __init__(self, name, age, sex, level, sal): super().__init__(name, age, sex) self.level = level self.sal = sal