继承初体验,寻找继承关系,继承背景下和对象属性查找顺序,派生,(子类派生出新的属性,并重新父类的属性),新式类与经典类,钻石继承。钻石继承实现修改jison模块数据类型。
面向对象阶段最重要的知识点:
#### 面向对象的三大特征:
1.继承
2.封装
3.多态
继承:
1.什么是继承?
继承指的是新建类的方法, 新建的类称之为子类或者派生类,
子类继承的类叫做父类,也称之为基类或超类.
继承的特征:
子类可以继承父类的属性(特征与技能), 并且可以派生出自己的属性(特征与技能).
******(面试问)
注意: 在python中,一个子类可以继承多个父类,其他语言只能一个子类继承一个父类.
2.为什么要继承?
继承的目的是为了减少代码冗余(减少重复代码).
3.如何实现继承?
1.首先要确定好谁是子类,谁是父类.
2.在定义类时, 子类 + (), ()内写父类,实现继承.
class 父:
xxx = 111
pass
class 子(父):
pass
1.继承初体验
class ParentClass1:
pass
class PaerntClass2:
pass
# 子类
class SubClass(PaerntClass2)
# 继承多个父类
class SubClass2(ParentClass1, ParentClass2):
pass
# 查看继承的父类: __bases__,是类的属性,用来查找当前类的父类.
print(SubClass1.__bases__) # (<class '__main__.ParentClass1'>,)
print(SubClass2.__bases__) # (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
2.寻找继承关系
一如何寻找继承关系:
要想寻找继承关系,首先要‘先抽象,再继承’。
什么是抽象?
抽象就是抽取相似的部分,称之为抽象。
- 先抽象(抽象思想):
奥巴马 ---> 人类 ---> 动物类
麦兜 ---> 猪类 ---> 动物类
小丁丁 ---> 狗类 ---> 动物类
抽象定义动物类,称之为父类.
特征:
眼睛,鼻子...
技能:
吃,喝,撒...
- 再继承(在程序中):
奥马巴对象 ---> 调用人类 ---> 继承动物类
麦兜对象 ---> 调用猪类 ---> 继承动物类
小丁丁对象 ---> 调用狗类 ---> 继承动物类
继承的关系:
对象是特征与技能的结合体.
类是一系列对象相同的特征与技能的结合体.
继承是一系列类相同的特征与技能的结合体.
'''
代码演示
# 不继承情况下:
# # 老师类: 名字,年龄,性别
# class OldboyTeacher:
# school = 'oldboy'
#
# def __init__(self, name, age, sex):
# self.name = name
# self.age = age
# self.sex = sex
#
# # 老师修改分数技能
# def change_score(self):
# print(f'老师[{self.name} 修改分数...]')
#
#
# # 学生类: 名字,年龄,性别
# class OldboyStudent:
# school = 'oldboy'
#
# def __init__(self, name, age, sex):
# self.name = name
# self.age = age
# self.sex = sex
#
# # 学生可以选择课程
# def choose_course(self, course):
# print(f'学生[{self.name}]选择课程[{course}]')
# 父类:
'''
抽象:
school
__init__(self, name, age, sex)
'''
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} 修改分数...]')
# 学生类: 名字,年龄,性别
class OldboyStudent(OldboyPeople):
# 学生可以选择课程
def choose_course(self, course):
print(f'学生[{self.name}]选择课程[{course}]')
stu1 = OldboyStudent('小丁丁', 95, 'female')
tea1 = OldboyTeacher('tank', 17, 'male')
print(stu1.name, stu1.age, stu1.sex)
print(tea1.name, tea1.age, tea1.sex)
3.继承背景下,对象属性查找顺序
在继承背景下,对象属性的查找顺序:
1.对象查找属性会先从对象的名称空间中查找.
2.若对象没有,则会去类里面找.
3.若当前类是子类,并且没有对象找的属性,会去父类中查找
注意: 对象查找属性,若子类有,不管父类有没有,以子类的为准.
# 验证对象属性的查找顺序
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
'''
4.派生
什么是派生?
派生指的是子类继承父类的属性,并且派生出新的属性.(*****)
子类派生出新的属性,若与父类的属性相同,则以子类的为准. 继承是谁与谁的关系, 指的是类与类的关系,子类与父类是从属关系.
# 验证对象属性的查找顺序
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.f1() # Soo.f1 若与父类的属性相同,则以子类的为准
5.子类派生出新的属性,并重新父类的属性
问题: 子类继承父类的__init__毫无意义. 不能添加属性,添加则报错用不了
列:
解决方式有两种:
方式一: 直接通过 父类.(调用)__init__,把__init__当做普通函数使用,传入对象与继承的属性.
方式二: super是一个特殊的类,在子类中调用super()会得到一个特殊的对象, 通过"."指向的是父类的名称空间.
注意:两种方式不要混合使用。
方法一:
# class OldboyPeoPle:
# def __init__(self,name,age,sex):
# self.name = name
# self.sge = 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
#
# class OldboyStudent(OldboyPeoPle):
# def __init__(self,name,age,sex,course):
# OldboyPeoPle.__init__(self,name,age,sex)
# self.course = course
#
# def choose_course(self):
# print(f'学生{self.name}选择课程{self.course}')
#
# tea1 = OldboyTeacher('tank',18,'male',9,'3.0')
# stu1 = OldboyStudent('小丁丁',20,'female','python')
# print(tea1.name,tea1.level) #tank 9
# print(stu1.name,stu1.course) #小丁丁 python
# stu1.choose_course() #学生小丁丁选择课程python
方法二:
class OldboyTeacher(OldboyPeople):
# 等级, 薪资
def __init__(self, name, age, sex, level, sal):
super().__init__(name, age, sex)
self.level = level
self.sal = sal
class OldboyStudent(OldboyPeople):
# 课程
def __init__(self, name, age, sex, course):
super().__init__(name, age, sex)
self.course = course
def choose_course(self):
print(f'学生{self.name}选择课程{self.course}')
# print(super)
tea1 = OldboyTeacher('tank', 17, 'male', 9, '3.0')
stu1 = OldboyStudent('小健健', 20, 'female', 'python')
print(tea1.name, tea1.level)
print(stu1.name, stu1.course)
stu1.choose_course()
6.新式类与经典类
新式类与经典类(了解):(面试)
在python2中,才会有新式类与经典类之分.
在python3中,所有的类都是新式类.
新式类:
继承object的类都称之为新式类.
python3中,子类不继承自定义的类,默认继承object.
经典类:
在python2中,凡是没有继承object的类都是经典类.
# 在python3:
# 新式类:
# class Foo(object):
# pass
# class Goo(Foo):
# pass
# # print(Foo.__bases__) # (<class 'object'>,)
# print(Goo.__bases__) # (<class 'object'>,)
7.钻石继承
钻石继承也可以称之为菱形继承(了解)面试可能会问。
再多集成的情况下形成的钻石继承(继承顺序)
经典类:
深度优先:
![](C:\Users\DELL\Pictures\Saved Pictures\QQ图片20191010153607.png)
新式类:
广度优先:
![](C:\Users\DELL\Pictures\Saved Pictures\QQ图片20191010153616.png)
# 验证
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
# 新式类: F-D-B-E-C-A-object #一级一级的查找
f1 = F()
f1.test()
# 经典类: F-D-B-A-E-C
![](C:\Users\DELL\Pictures\Saved Pictures\QQ图片20191010153625.png)
8.钻石继承实现修改jison模块数据类型
import json
from datetime import date,datetime
print(json.JSONEncoder)
print(datetime.today())# 当前时间
print(date.today()) #当前日期
python内置函数,可以传两个参数,判断参数一是否式参数二的一个实例
# 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)