继承
Downwards is the only way forwards .——《盗梦空间》
面向对象阶段最重要的知识点:继承、封装、多态
1.什么是继承?
指新建类的方法,新建的类称之为子类或者派生类,子类继承的类叫做父类,也称之为基类或者超类。
继承特征:
子类可以继承父类的属性(特征与技能),并且可以派生出自己的属性(特征与技能)。
在python中一个子类可以继承多个父类,其他语言一个子类只可以继承一个父类
2.为什么要继承?
继承的目的是为了减少代码的冗余(减少重复代码)
3.如何实现继承?
1.首先要确定好谁是子类谁是父类.
2.在定义类时子类+(),()内写父类,实现继承.
class 父类:
pass
class 子类(父类):
pass
#父类
class ParentClass1:
pass
class ParentClass2:
pass
#子类
class Subclass1(ParentClass1):
pass
class Subclass2(ParentClass1,ParentClass2):
pass
print(Subclass2.__bases__)
#(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
#查看继承的父类:__bases__,是类的属性,用来查找自己的父类,通过元组的形式返回所继承的父类
寻找继承关系
如何寻找继承关系?
要想寻找继承关系,首先抽象再继承。
——先抽象(抽象思想):
奥巴马——》人类——》动物类
麦兜——》猪类——》动物类
小丁丁——》狗类——》动物类
抽象定义动物类,父类。
特征:眼睛、鼻子...
技能:
吃喝...
——再继承(在程序中)
继承的关系:
对象:特征与技能的结合体
类:一系列特征与技能的结合体
继承:一系列类相同的特征与技能的结合体
class SchoolPeople:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class Students(SchoolPeople):
def choose_course(self):
print(f'{self.name} is choosing course.')
class Teachers(SchoolPeople):
def teach(self):
print(f'{self.name} is teaching students.')
stu1 = Students('xiaoming','15','男')
stu1.choose_course()
xiaoming is choosing course.
继承背景下对象属性的查找顺序
对象查找属性先从自己的名称空间查找,若当前类是子类,并且没有该属性,就去父类中查找,如果父类也没有就报错__class__查看当前对象的类。
注意:对象查找属性不管父类有没有这个属性,只要子类有就不会去父类中查找
查看对象名称空间
print(tea1._dict__)
查看对象的属性,查看当前对象的类__class_
查看子类名称空间
print(tea1._class__.__dict__)
查看父类名称空间
print(tea1.__class__.__bases__[0].__dict_)#查看第一个父类的名称空间
#验证对象属性的查找顺序
class Foo:
def f1(self):
print('Foo.f1')
def f2(self):
print('Foo.f2')
self.f1()
class Soo(Foo):
def f1(self):
print('Soo.f1')
soo_obj = Soo()
soo_obj.f2()
'''
Foo.f2
Soo.f1
'''
派生
什么是派生?
派生指子类继承父类的属性,并且派生自己的属性。
如果子类和父类都有这个属性,以子类自己的属性为准。
继承指的是类与类的关系,子类与父类是从属关系。
子类派生出新的属性,并重用父类的属性
class SchoolPeople:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(SchoolPeople):
def __init__(self,name,age,gender,level,sal):
SchoolPeople.__init__(self,name,age,gender)#重用父类的属性
self.level = level#派生出的属性
self.sal = sal#派生出的属性
tech1 = Teacher('xiaohua','17','男','10','5w')
print(tech1.level)
重用父类属性的两种方式
方式一:
直接通过父类.(调用)__init__,把__init__当做普通函数使用,传入对象与继承的属性,如上例中的重用。
方式二:
super是一个特殊的类,在子类中调用super()会得到一个特殊的对象,通过“.”
指向父类的名称空间。
class SchoolPeople:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(SchoolPeople):
def __init__(self,name,age,gender,level,sal):
super().__init__(name,age,gender)#重用父类的属性(注意括号里面没有self)
self.level = level#派生出的属性
self.sal = sal#派生出的属性
注意:两种方式不要混着使用
新式类与经典类
新式类与经典类(了解)(面试会问)
在python2中才有经典类,没有继承object的类都是经典类。
python3中都是新式类,继承object类的都是新式类,py3中默认继承object类。
钻石继承(菱形继承)
关于mro()
mro():是object——》type的函数,用来查看多继承情况下,当前类的继承顺序, .mro()方法其实就是在查找mro()方法
一个子类如果继承多个父类,属性的查找顺序是从左向右依次查找,最后找object
钻石继承
钻石继承(菱形继承):钻石继承就是一个子类有多个父类,每个父类又有多个不同的父类......这些父类的祖先最终是同一个祖宗。(面试问)
在多继承情况下可能会出现钻石继承的情况。
钻石继承下对象属性的查找顺序
--经典类——》深度优先:从左向右查找,一条分支找到底,若果没找到就去另一条分支继续找。
——新式类——》广度优先:从左向右查找,和经典类的区别是最后找所有分支共同的父类
验证查找顺序代码
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(B):
def test(self):
print('from D')
class E(C):
def test(self):
print('from E')
class F(D,E):
# def test(self):
# print('from F')
pass
f1=F()
f1.test()
print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
#新式类继承顺序:F->D->B->E->C->A
#经典类继承顺序:F->D->B->A->E->C
#python3中统一都是新式类
#pyhon2中才分新式类与经典类
通过继承实现修改json模块数据类型
通过继承实现为json增加数据类型:
import json
from datetime import date ,datetime
print(json.JSONDecoder)#<class 'json.decoder.JSONDecoder'>
print(datetime.today())#当前时间
print(date.today())#当前日期
#从开发者的角度考虑,可以将json不支持的数据类型转成json支持的是数据类型
#如:
'''dict1 = {
'name':'tank',
'today':str(datetime.today()),
'today1':str(date.today())
}
res = json.dumps(dict1)
print(res)
#{"name": "tank", "today": "2019-10-10 14:30:26.967368", "today1": "2019-10-10"}
从开源者的角度考虑,Python time strftime() 函数接收以时间元组,并返回以可读字符串表示的当地时间,
格式由参数format决定。'''
class MyJson(json.JSONEncoder):
def default(self,o):
if isinstance(o,datetime):#判断o是否是datetime的一个实例对象
return o.strftime('%Y-%m-%d %X')
elif isinstance(o,date):
return o.strftime('%Y-%m-%d')
else:
return super().default(self,o)#在json中也有default这个方法
dict1 = {
'name':'tank',
'today':datetime.today(),
'today1':date.today()
}
res = json.dumps(dict1,cls = MyJson)#cls=None,默认指向的是原json的JSONEncoder,加上之后优先使用外面的类
print(res)
总结
1.什么是继承?
继承指的是新建类的方法, 新建的类称之为子类或者派生类,子类继承的类叫做父类,也称之为基类或超类.
继承的特征:
子类可以继承父类的属性(特征与技能), 并且可以派生出自己的属性(特征与技能).
2.继承的目的:
继承的目的是为了减少代码冗余(减少重复代码).
3.什么是抽象?
抽象指的是抽取相似的部分,称之为抽象.
4.继承的关系:
对象是特征与技能的结合体.
类是一系列对象相同的特征与技能的结合体.
继承是一系列类相同的特征与技能的结合体.
5.在继承背景下,对象属性的查找顺序:
1.对象查找属性会先从对象的名称空间中查找.
2.若对象没有,则会去类里面找.
3.若当前类是子类,并且没有对象找的属性,会去父类中查找
6.什么是派生?
派生指的是子类继承父类的属性,并且派生出新的属性.(*****)
子类派生出新的属性,若与父类的属性相同,则以子类的为准.
继承是谁与谁的关系, 指的是类与类的关系,子类与父类是从属关系.
7.子类派生出新的属性,并重用父类的属性:
- 直接通过 父类.(调用)init,把__init__当做普通函数使用,传入对象与继承的属性.
- super是一个特殊的类,在子类中调用super()会得到一个特殊的对象,
8.什么经典类与新式类:
继承object的类都称之为新式类.
在python2中,凡是没有继承object的类都是经典类.
9.在多继承的情况下形成的钻石继承 (继承顺序)
- 经典类:
深度优先
- 新式类:
广度优先