继承
什么是继承?(What)
- 继承指的是新建类的方法,新建的类称之为子类或派生类,子类继承的类叫做父类,也称之为基类或超类
- 继承的特征:子类可以继承父类的属性(特征与技能),并且可以派生出自己的属性(特征与技能)
为什么要继承?(What)
- 较少代码冗余
如何实现继承(How)
- 首先确定好谁是子类,谁是父类
- 在定义类时, 子类 + () , () 内写父类,实现继承
查看继承的父类
class ParentClass1:
pass
class ParentClass2:
pass
class SubClass1(ParentClass1):
pass
print(SubClass1.__bases__) # __bases__ 是类的属性,用来查找当前类的父类
class SubClass2(ParentClass1,ParentClass2): #在python中一个子类可以继承多个父类
pass
print(SubClass2.__bases__)
# __bases__ 是类的属性,用来查找当前类的父类
#在python中一个子类可以继承多个父类---python中独有,其他语言一个子类只继承一个父类,面试会问
'''
(<class '__main__.ParentClass1'>,)
(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
'''
寻找继承关系
如何寻找继承关系
- 先抽象,再继承
什么是抽象
- 抽取相似的部分
- 奥巴马-->人类-->动物类
- 麦兜-->猪类-->动物类
- 小丁丁-->狗类-->动物类
- 抽象定义动物类,称之为父类
- 特征:
- 眼睛,鼻子,...
- 技能
- 吃,喝...
- 特征:
- 继承
- 奥巴马对象<--调用人类<--继承动物类
- 麦兜对象<--调用猪类<--继承动物类
- 小丁丁对象<--调用狗类<--继承动物类
继承关系
- 对象是特征与技能的结合体
- 类是一系列对象中相同的特征与技能的结合体
- 继承是一系类中相同的特征与技能的结合体
在继承关系下对象属性的查找顺序
- 先从对象名称空间查找
- 没有再从对象所属子类查找
- ,没有最后从父类中查找
在某一层找到就不会继续寻找
# 父类
class OldboyPeople:
school = 'oldboy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
# 子类
class OldboyTeacher(OldboyPeople):
# 老师修改分数技能
def change_score(self):
print(f'老师[{self.name} 修改分数...]')
teacher = OldboyTeacher('tank', 17, 'male')
print(teacher.__class__) #查看对象所属的类
print(teacher.__class__.__dict__) #查看对象所属类的名称空间
print(teacher.__class__.__bases__) #查看对象所属的类的父类
print(teacher.__class__.__bases__[0].__dict__) #查看对象所属的类的第一个父类的名称空间
print(id(teacher.school))
print(id(OldboyPeople.school))
'''
<class '__main__.OldboyTeacher'>
{'__module__': '__main__', 'change_score': <function OldboyTeacher.change_score at 0x00000185B7F9EB70>, '__doc__': None}
(<class '__main__.OldboyPeople'>,)
{'__module__': '__main__', 'school': 'oldboy', '__init__': <function OldboyPeople.__init__ at 0x00000185B7F9EAE8>, '__dict__': <attribute '__dict__' of 'OldboyPeople' objects>, '__weakref__': <attribute '__weakref__' of 'OldboyPeople' objects>, '__doc__': None}
2219246848072
2219246848072
'''
派生
- 派生指的是子类继承父类的属性并且派生出新的属性
- 子类派生出新的属性,若与父类的属性相同,则以子类为准
- 继承指的是子类与父类之间的从属关系
子类派生出新的属性并重用父类
方式一
#通过 父类.__init__ ,把 __init__ 当做普通函数使用,传入对象与继承的函数
# 父类
class OldboyPeople:
school = 'oldboy'
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,salary):
OldboyPeople.__init__(self,name,age,sex)
self.level = level
self.salary = salary
teacher = OldboyTeacher('tank',18,'male',9,'3.0w')
print(teacher.__dict__)
'''
{'name': 'tank', 'age': 18, 'sex': 'male', 'level': 9, 'salary': '3.0w'}
'''
方式二
#super是一个特殊的类,在子类中调用super()会得到一个特殊的对象,该对象通过 "." 指向父类的名称空间
# 父类
class OldboyPeople:
school = 'oldboy'
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,salary):
super().__init__(name,age,sex)
self.level = level
self.salary = salary
teacher = OldboyTeacher('tank',18,'male',9,'3.0w')
print(teacher.__dict__)
'''
{'name': 'tank', 'age': 18, 'sex': 'male', 'level': 9, 'salary': '3.0w'}
'''
super类的使用方法---super(type,object)与super()
super(type,object)
#super(type,object),type作用是定义在__mro__数组中的那个位置开始找,obj定义的是用哪个类的__mro__元素
class A(object):
def fun(self):
print('A.fun')
class B(object):
def fun(self):
print('B.fun')
class C(object):
def fun(self):
print('C.fun')
class D(A,B):
def fun(self):
print('D.fun')
class E(B, C):
def fun(self):
print('E.fun')
class F(D, E):
def fun(self):
print('F.fun')
print(F.mro())
print(B.mro())
super(B , B()).fun() #会报错
'''
AttributeError: 'super' object has no attribute 'fun'
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.A'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]
[<class '__main__.B'>, <class 'object'>]
'''
super
super()事实上是懒人版的super(type , obj),这种方式只能用在类体内部,Python会自动把两个参数填充上,type指代当前类,obj指导当前类的实例对象,相当于super(class , self)
新式类与经典类
在python2中,才会有新式类与经典类之分,在python3中,所有类都是新式类---面试会问
新式类
- 继承object的类都称之为新式类
- python3中所有的类默认继承object
class Foo(object):
pass
print(Foo.__bases__)
class Foo:
pass
print(Foo.__bases__)
'''
(<class 'object'>,)
(<class 'object'>,)
'''
经典类
在python2中,凡是没有继承object的类都是经典类
#python2
'''
>>> class Foo(object):
... pass
...
>>> Foo.__bases__
(<type 'object'>,)
>>> class Foo:
... pass
...
>>> Foo.__bases__
()
'''
mro()
---Method Resolution Order (方法解析顺序)-->属于object-->属于type
python内置的函数用来查看在多继承情况下,当前类的继承顺序
class A:
x = 'A'
pass
class B:
x = 'B'
pass
class C(A,B):
pass
print(C.x)
print(C.__mro__)
print(C.mro())
'''
A
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
'''
菱形继承
在多继承的情况下形成(继承顺序)
- 经典类
- 深度优先
- 新式类
- 广度优先
验证
# python2
class A:
# def test(self):
# print('from A')
pass
class B(A):
# def test(self):
# print('from B')
pass
class C(A):
def test(self):
print('from C')
pass
class D(B):
# def test(self):
# print('from D')
pass
class E(C):
# def test(self):
# print('from E')
pass
class F(D,E):
# def test(self):
# print('from F')
pass
f1 = F()
f1.test()
#经典类(深度优先): F-->D-->B-->A-->E-->C
#新式类(广度优先): F-->D-->B-->E-->C-->A
通过继承机制修改json数据格式
import json
from datetime import date,datetime
print(date.today())
print(datetime.today())
print(type(date.today()))
print(type(datetime.today()))
print('*'*100)
dic = {'name':'蔡启龙','date':date.today(),'today':datetime.today()}
# print(json.dumps(dic)) #TypeError: Object of type 'date' is not JSON serializable
#开发者角度:直接转成str
#开源者角度:修改源码
#isinstance:python,可以穿两个参数,判断参数一是否是参数二的一个实例
a = date(2019,10,11)
print(type(a))
b = a.strftime('%Y-%m-%d %X')
print(b)
print(type(b))
print('*'*100)
class MyJson(json.JSONEncoder):
def default(self, o):
if isinstance(o,type(date.today())):
return o.strftime('%Y-%m-%d %X')
if isinstance(o,type(datetime.today())):
return o.strftime('%Y-%m-%d %X')
#继承父类的default方法的功能
return super().default(o)
res = json.dumps(dic,cls=MyJson)
print(res)
print('*'*100)
print(json.loads(res))
'''
2019-10-11
2019-10-11 00:20:52.540284
<class 'datetime.date'>
<class 'datetime.datetime'>
****************************************************************************************************
<class 'datetime.date'>
2019-10-11 00:00:00
<class 'str'>
****************************************************************************************************
{"name": "u8521u542fu9f99", "date": "2019-10-11 00:00:00", "today": "2019-10-11 00:20:52"}
****************************************************************************************************
{'name': '蔡启龙', 'date': '2019-10-11 00:00:00', 'today': '2019-10-11 00:20:52'}
'''