day21--继承--派生
继承:
什么是继承?
继承是一种新建类的方式,新建的类称之为字类或派生类,继承的父类称之为基类或超类。
在python中,一个子类可以继承多个父类。
在其他语言中,一个子类只能继承一个父类。
继承的作用:
解决代码的冗余。
如何实现继承?
1.先确认谁是子类,谁是父类。
2.在定义类子类时,子类名(父类名)。
# 父类
class Father1:
x = 1
pass
class Father2:
pass
#子类
class Sub(Father1, Father2):
pass
#子类.__bases__查看父类
print(Sub.__bases__)
print(Sub.x)
如何寻找继承关系:
1.确认谁是子类
2.确认谁是父类
-- 抽取对象之间相似的部分总结出类。
--抽取类之间相似的部分,总结出父类。
#代码冗余:
#老师类
class OldboyTeacher:
school = 'oldboy'
country = 'China'
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'
country = 'China'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
#学生选课程
def choose_course(self):
print(f'学生{self.name}正在选择课程...')
#学生类
stu1 = OldboyStudent('AA', 19, 'female')
print(stu1.school, stu1.name, stu1.age, stu1.sex) #oldboy AA 19 female
#老师
tea1 = OldboyTeacher('tank', 18, 'male')
print(tea1.school, tea1.name, tea1.age, tea1.sex) # oldboy tank 18 male
# 解决代码冗余问题
#老男孩人类
class OldboyPeople: #我们经过分析可以得到上面学生类和老师类共同拥有 的特征,我们定义老男孩人类的父类。
school = 'oldboy'
country = 'China'
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):
print(f'学生{self.name}在选择课程...')
stu1 = OldboyStudent('AA', 39, 'female')
print(stu1.school, stu1.name, stu1.age, stu1.sex)#oldboy AA 39 female
tea1 = OldboyTeacher('大脸', 75, 'female')
print(tea1.school, tea1.name, tea1.age, tea1.sex)#oldboy 大脸 75 female
继承背景下对象属性的查找顺序
注意: 程序的执行顺序是由上到下,父类必须定义在子类的上方。
-- 在继承背景下,对象属性的查找顺序:
1.先从对象自己的名称空间中查找
2.对象中没有,从子类的名称空间中查找。
3.子类中没有, 从父类的名称空间中查找,若父类没有,则会报错!
派生
指的是子类继承父类的属性与方法,并且派生出自己独有的属性与方法。
若子类中的方法与父类的相同,优先用子类的。
#父类:
class Foo:
def f1(self):
print('from Foo.f1...')
def f2(self):
print('from Foo.f2...')
self.f1()
#子类
class Bar(Foo):
def f1(self):
print('from Bar.f1...')
def func(self):
print('from Bar.func...')
# bar_obj = Bar()
# bar_obj.f1() # from Bar.f1...
# bar_obj.func() # from Bar.func...
# bar_obj.f2() # from Foo.f2...
bar_obj = Bar()
bar_obj.f2() #from Foo.f2...
#from Bar.f1... #因为子类和父类中的方法名一样,优先使用子类名,
子类继承父类并重用父类的属性与方法
子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法。
问题: 子类重写父类的_ _ init _ _ 导致代码更加冗余
解决问题:子类重用父类的属性,并派生出新的属性
--两种方式:
--1.直接引用父类的_ _ init _ _为其传参,并添加子类的属性。
--2.通过super来指向父类的属性。
--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, sal):
# self.name = name
# self.age = age
# self.sex = sex
# #类调用类内部的__init__,值时一个普通函数
OldboyPeople.__init__(self, name, age, sex)
self.sal = sal
def change_score(self):
print(f'老师{self.name}修改分数...')
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, girl):
OldboyPeople.__init__(self, name, age, sex)
self.girl = girl
def choose_course(self):
print(f'学生{self.name}选择课程...')
tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
print(tea1.name, tea1.age, tea1.sex, tea1.sal)
stu1 = OldboyStudent('姚玉鑫', 28, 'male', '凤姐')
print(stu1.name, stu1.age, stu1.sex, stu1.girl)
#方法二
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, sal):
super().__init__(name, age, sex)
self.sal = sal
def change_score(self):
print(f'老师{self.name}修改分数...')
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, girl):
super().__init__(name, age, sex)
self.girl = girl
def choose_course(self):
print(f'学生{self.name}选择课程...')
tea1 = OldboyTeacher('tank', 17, 'male', 15000000)
print(tea1.name, tea1.age, tea1.sex, tea1.sal)
stu1 = OldboyStudent('姚玉鑫', 28, 'male', '凤姐')
print(stu1.name, stu1.age, stu1.sex, stu1.girl)
经典类与新式类(了解)
-
新式类:
--1.凡是继承object的类或子孙类都是新式类。
--2.在python3中所有的类都默认继承object。
-
经典类:
--1.在python2中才会有经典类与新式类之分。
--2.在python2中,凡是没有继承object的类,都是经典类。
supre严格遵循mro继承顺序
调用mro返回的是一个继承序列: (了解知识点)
super的继承顺序严格遵循mro继承序列。
在python3中提供了一个查找新式类查找顺序的内置方法. mro(): 会把当前类的继承关系列出来。
class Father1:
x = 10
pass
class Father2:
x = 20
pass
#多继承的情路况下:从左到右
class Sub(Father1, Father2):
def __init__(self):
print(super().__delattr__)
print(Sub.mro())
obj = Sub()
print(object)
多继承情况下造成 “钻石继承”
mro的查找顺序:
新式类:
广度优先
经典类:
深度优先
# 了解:
# 新式类:
class A(object):
# 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
# print(F.mro())
obj = F()
obj.test()