面向对象三大特性1-继承
目录
面向对象的三大特性之继承
一、什么是继承?
继承:是一种新建类的方式,新建的类称之为子类或者派生类,子类继承的类叫做父类,也可以称之为基类或者超类。
继承的特征
子类可以继承父类的属性(技能与特征),并且可以派生出自己的属性(特征与技能)。
class Parent:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
class Son(Parent):
def choose_course(self, course):
print(f'学生[{self.name}]选择课程[{course}]')
注意:在Python中,一个子类可以继承多个父类,其他语言只能一个子类继承一个父类。
class Parent1:
pass
class Parent2:
pass
class Sub1(Parent1, Parent2):
pass
二、为什么要继承?
继承的目的是为了减少代码冗余(减少重复代码)。
三、如何实现继承?
- 首先要确定好谁是子类,谁是父类。
- 在定义类时,子类 + (),()内写父类,实现继承。
四、查看继承的父类
# 可以用__bases__,这是类的属性,用来查找当前类的父类.
print(Son.__bases__) # (<class '__main__.Parent'>,)
print(Sub1.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
五、继承与抽象
1、如何寻找继承关系
要想寻找继承关系,首先要 "先抽象,再继承"。
2、什么是抽象
抽象指的是抽取相似的部分,称之为抽象。
举例:
- 先抽象(抽象思想):
奥巴马 ---> 人类 ---> 动物类
麦兜 ---> 猪类 ---> 动物类
旺财 ---> 狗类 ---> 动物类
抽象定义动物类,称之为父类。
特征:
眼睛,鼻子...
技能:
吃,喝,撒...
- 再继承(在程序中):
奥马巴对象 ---> 调用人类 ---> 继承动物类
麦兜对象 ---> 调用猪类 ---> 继承动物类
小丁丁对象 ---> 调用狗类 ---> 继承动物类
3、什么是继承
继承的关系:
对象 是特征与技能的结合体。
类 是一系列对象相同的特征与技能的结合体。
继承 是一系列类相同的特征与技能的结合体。
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)
# 小丁丁 95 female
# tank 17 male
六、继承后对象属性查找顺序
对象名称空间 -->子类名称空间 --> 父类名称空间
# 父类
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} 修改分数...]')
tea1 = OldboyTeacher('tank', 17, 'male')
print(tea1.school)
# 查看对象名称空间
print(tea1.__dict__)
# __class__: 对象的属性,查看当前对象的类.
# 查看子类名称空间
print(tea1.__class__.__dict__)
# 查看父类名称空间
print(tea1.__class__.__bases__[0].__dict__)
'''
oldboy
{'name': 'tank', 'age': 17, 'sex': 'male'}
{'__module__': '__main__', 'change_score': <function OldboyTeacher.change_score at 0x00000122CCFECDC8>, '__doc__':None}
{'__module__': '__main__', 'school': 'oldboy', '__init__':<function OldboyPeople.__init__ at 0x00000122CCFE6B88>,'__dict__': <attribute '__dict__' of'OldboyPeople' objects>, '__weakref__': <attribute'__weakref__' of 'OldboyPeople' objects>, '__doc__': None}
'''
七、派生
1、什么是派生
派生指的是子类继承父类的属性,并且新增新的属性。
子类派生出的新属性,若与父类的属性名相同,则以子类的为准。
继承是谁与谁的关系,指的是类与类的关系,子类与父类是从属关系。
2、派生子类更新父类属性
2.1 方法一:调用父类init
直接调用 父类.__init__()
,把__init__当做普通函数使用,传入对象与继承的属性。
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', 17, 'male', 9, '3.0')
stu1 = OldboyStudent('小健健', 20, 'female', 'python')
print(tea1.name, tea1.level)
print(stu1.name, stu1.course)
stu1.choose_course()
'''
tank 9
小健健 python
学生小健健选择课程python
'''
2.2 方法二:super
super():
super是一个特殊的类,在子类中调用super()会得到一个特殊的对象,通过"."指向的是父类的名称空间.
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}')
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()
'''
tank 9
小健健 python
学生小健健选择课程python
'''
八、新式类和经典类(了解)
在python2中,才会有新式类与经典类之分.
在python3中,所有的类都是新式类.
1、新式类
继承object的类都称之为新式类.python3中,子类不继承自定义的类,默认继承object.
2、经典类
在python2中,凡是没有继承object的类都是经典类.
3、mro函数
mro():
属于object--> type的函数。
在多继承的情况下 , 用来查看当前类的继承顺序.
class A:
pass
class B:
pass
# 多继承情况下:
class C(A, B):
pass
print(C.mro())
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
九、钻石继承(了解)
钻石继承也可以称之为菱形继承
- 在多继承的情况下形成的钻石继承的继承顺序:
- 经典类:深度优先
- 新式类:广度优先
# 验证
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 - E-C-A -object
# 经典类: F- D-B-A - E-C
十、通过继承修改json模块的数据类型
import json
from datetime import date, datetime
print(json.JSONEncoder)
print(datetime.today()) # 当前时间
print(date.today()) # 当前日期
# 开源者的角度: 修改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)
'''
<class 'json.encoder.JSONEncoder'>
2019-10-10 16:26:11.875435
2019-10-10
{"name": "tank", "today": "2019-10-10 16:26:11", "today2": "2019-10-10"}
'''