继承
1.1什么是继承?
-继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或者超类。
-在python中一个子类可以继承多个父类,(面试的时候可能会问)
-在其他语言中,一个子类只能继承一个父类
1.2继承的作用?
-减少代码的冗余
1.3如何实现继承?
1.先确认谁是子类,谁是父类
2.在定义子类时,子类名(父类名)
#父类
class Father1:
x = 1
pass
class Father2:
pass
#子类
class Sub(Father1,Father2):
pass
#子类查看父类 __bases__
print(Sub.__bases__)
print(Sub.x)
>>>>>>>>>>>>>>>>>
(<class '__main__.Father1'>, <class '__main__.Father2'>)
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:
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('huyu',28,'male')
print(stu1.school,stu1.name,stu1.age,stu1.sex)
tea1 = OldboyTeacher('tank',17,'male')
print(tea1.school,tea1.name,tea1.age,tea1.sex)
>>>>>>>>>>>
oldboy huyu 28 male
oldboy tank 17 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('yuyu',20,'female')
print(stu1.school,stu1.name,stu1.age,stu1.sex)
tea1 = OldboyTeacher('tank',25,'male')
print(tea1.school,tea1.name,tea1.age,tea1.sex)
>>>>>>>>>>>>>>>>>>>>>
oldboy yuyu 20 female
oldboy tank 25 male
3.在继承背景下的对象属性的查找顺序
注意:
-程序的执行顺序是由上到下,父类必须定义在子类的上方
-在继承的背景下,对象的属性查找顺序:
1.先从对象自己的名称空间中查找;
2.对象中没有,从子类的名称空间中查找;
3.子类中没有,从父类的名称空间中查找,若父类没有,则会报错!
#父类
class Goo:
x = 10
pass
#子类
class Foo(Goo):
# x = 100
pass
foo_obj = Foo()
foo_obj.x = 20
print(foo_obj.x)
print(foo_obj.__dict__)
print(Foo.__dict__)
print(Goo.__dict__)
>>>>>>>>>>>>>>>>>>>
20 #####如果对象有,则先用对象里面分 如果里面没有,则是用子类的,如果子类里面没有的 则用父类的
{'x': 20}####这个因为对象名称空间中有
{'__module__': '__main__', '__doc__': None}####子类的
{'__module__': '__main__', 'x': 10, '__dict__': <attribute '__dict__' of 'Goo' objects>, '__weakref__': <attribute '__weakref__' of 'Goo' objects>, '__doc__': None}#####这个是父类的
4.派生
定义:指的是子类继承父类的属性和方法,并且派生出自己独有的属性和方法。
若子类中大方法与父类相同,优先用子类
#父类
class Foo():
def f1(self):
print('from Foo.f1...')
def f2(self):
print('from Foo.f2...')
#子类
class Bar(Foo):
def f1(self):
print('from Bar.f1...')
def func(self):
print('from Bar.func...')
bar_obj = Bar()
bar_obj.f1()
bar_obj.f2()
bar_obj.func()
>>>>>>>>>>>>>>>
from Bar.f1...
from Foo.f2...
from Bar.func...
#父类
class Foo():
def f1(self):
print('from Foo.f1...')
def f2(self):#################正常的先调用父类的f2,这个里面的self相当于 bar_f1传入的是它的本身
print('from Foo.f2...')
self.f1()### 相当于bar_obj.f1() 调用的是自身的f1
#子类
class Bar(Foo):
def f1(self):
print('from Bar.f1...')
def func(self):
print('from Bar.func...')
bar_obj = Bar()
bar_obj.f2()
>>>>>>>>>>>>>>
from Foo.f2...
from Bar.f1...
5.子类继承父类,派生出自己的属性和方法,并且重用父类的属性和方法
#w问题:子类重写父类的__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,sal):
self.name = name
self.age = age
self.sex = sex
self.sal = sal
def change_score(self):
print(f'老师{self.name}修改分数...')
class OldboyStudent(OldboyPeople):
def __init__(self,name,age,sex,girl):
self.name = name
self.age = age
self.sex = sex
self.girl = girl
def choose_course(self):
print(f'老师{self.name}修改分数...')
tea1 = OldboyTeacher('tank',17,'male',150000)
stu1 = OldboyStudent('yaoyuxi',28,'male','美女')
print(tea1.name,tea1.age,tea1.sex,tea1.sal)
print(stu1.name,stu1.age,stu1.sex,stu1.girl)
###以上方法做的代码比较冗余 我们可以用更加简便的方法来操作
解决上述的问题 ;
-我们可以用子类重用父亲的属性,并派生出新的属性
两种方式:
1.直接引用父类的——init--为其传参,并添加子类的属性;
2.通过super来指向父类的属性super().init
-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):##把参数要传入
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',150000)
print(tea1.name,tea1.age,tea1.sex,tea1.sal)
stu1 = OldboyStudent('yaoyuxi',28, 'female','美女')
print(stu1.name,stu1.age,stu1.sex,stu1.girl)
>>>>>>>>>>>>>>>>>>>
tank 17 male 150000
yaoyuxi 28 female 美女
#第二种方法
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)####特殊的对象,指向的是父类的名称空间
会将调用类传入的对象当作第一个参数传给——— init————()
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',150000)
print(tea1.name,tea1.age,tea1.sex,tea1.sal)
stu1 = OldboyStudent('yaoyuxi',28, 'female','美女')
print(stu1.name,stu1.age,stu1.sex,stu1.girl)
>>>>>>>>>>>>>>>>>>>>>>>>
tank 17 male 150000
yaoyuxi 28 female 美女
经典式和新式类
了解类的
工作上遇不到 ,但是面试上会问的
-1.新式类
1.凡是继承了object的类或者子孙类的都是新式类
2.在python3中,所有类默认继承的都是object
-2.经典类
1.在python2中的才会有经典类和新式类之分
2.在python2中,凡是没有继承object的类,都是经典类
class User(object):####这个就是新式类的
pass
class Sub(User):
pass
print(User.__dict__)
7.super严格遵循mro的继承顺序
了解的知识点
super的继承顺序严格遵循mro的继承序列
多继承的情况下:从左向右
class Father1:
x = 20
pass
class Father2:
x = 40
pass
class Sub(Father1,Father2):
pass
obj = Sub()
print(Sub.mro())
print(object)
>>>>>>>>>>>>>>
[<class '__main__.Sub'>, <class '__main__.Father1'>, <class '__main__.Father2'>, <class 'object'>] #####这个顺序就是Father1-->Father2从左 向右的查找
<class 'object'>
# 注意: super()会严格按照mro列表的顺序往后查找
# class A:
# def test(self):
# print('from A.test')
# super().test()
#
#
# class B:
# def test(self):
# print('from B.test')
#
#
# class C(A, B):
# pass
#
#
# c = C()
# # 检查super的继承顺序
# print(C.mro())
#
# # 去A找,有的话打印,然后super又执行了test,根据mro中查找打印B类中test。
# c.test()
# '''
# from A.test
# from B.test
# '''
8.mro
多继承的情况下造成等的“钻石继承”
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####这个就是新式类的 查找的顺序 最后才找到顶层的A
# print(F.mro())
obj = F()
obj.test()
>>>>>>>>>>>>>
from F ####先从F里面来找
这个新式类的属性查找:广度优先
这个是经典类的属性查找:深度优先