继承
1.什么是继承?
继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或超类
在python中,一个子类可以继承多个父类(面试题)
在其他语言中,一个子类只能继承一个父类
2.继承的作用?
减少代码的冗余
3.如何实现继承?
1)先确认呢谁是子类,谁是父类
2) 在定义类子类时,子类名(父类名)
父类
class Father1:
pass
class Father2:
pass
class Father3:
pass
子类
class Sub(Father1,Father2,Father3):
pass
# 子类。__bases__查看父亲
print(Sub.__bases__)
print(Sub.x)
4.如何寻找继承关系:
确认谁是子类
确认谁是父类
先抽象,再继承:
抽取对象之间相似的部分,总结出类
抽取类之间相似的部分,总结出父类
代码冗余
# 老师类
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}正在选择课程。。。')
解决代码冗余
# 老男孩人类
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}正在选择课程...')
程序的执行顺序是由上而下,父类必须定义在子类的上方
在继承背景下,对象属性的查找顺序:
1.先从对象自己的名称空间中查找
2.对象中没有,从子类的名称空间中查找
3.子类中没有,从父类的名称空间中查找,若父类没有,则会报错
ps: 对象中添加属性的操作
坑:并不是修改子类的属性
派生:
指的是子类继承父类的属性与方法,并且派生出自己独有的属性和方法
若子类中的方法名与父类的相同有先用子类的
# 父类
class Foo:
def f1(self):
print('from Foo.f1...')
def f2(self): # self ---> bar_obj
print('from Foo.f2...')
# bar_obj.f1() ---> 对象自己找 ---> Bar ---> Foo
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 __会导致代码更加冗余
代码冗余
# 老师类
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}正在选择课程。。。')
解决问题: 子类重用父类的属性,并派生出新的属性
两种方式:
1.直接引用父类的__ init __为其传参,并且添加子类的属性
2.通过super来指向父类的属性
-super()是一个特殊的类,调用super得到一个对象,该对象指向父类的名称空间
ps: 使用哪一种都可以,但不能两种方式混合使用
第一种
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 __init__(self, name, age, sex, sal):
# 类调用内部的__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, hobby):
OldboyPeople.__init__(self, name, age, sex)
self.hobby = hobby
def choose_course(self):
print(f'学生{self.name}进行选课!')
teacher = OldboyTeacher('tank', 28, 'female', 120000)
print(teacher.name, teacher.sex, teacher.age, teacher.sal)
第二种
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 __init__(self, name, age, sex, sal):
# 类调用内部的__init__只是普通的函数
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, hobby):
super().__init__(name, age, sex)
self.hobby = hobby
def choose_course(self):
print(f'学生{self.name}进行选课!')
teacher = OldboyTeacher('tank', 28, 'female', 120000)
print(teacher.name, teacher.sex, teacher.age, teacher.sal)
经典类与新式类:
新式类:
1.凡是继承object的类或子孙类都是新式类
2.在python3中所有的类都默认继承object
经典类:
1.在python2中才会有经典类与新式类之分
2.在python2中,凡是没有继承object的类,都是经典类
# class User(object):
# pass
python3中所有的类都是继承object
class User:
x = 10
pass
class Sub(User):
pass
print(User.__dict__)
{'__module__': '__main__', 'x': 10, '__dict__': <attribute '__dict__' of 'User' objects>, '__weakref__': <attribute '__weakref__' of 'User' objects>, '__doc__': None}
python2中
#!/usr/bin/u/ubv/a python
# _*_ coding:utf8 _*_
class User(object):
x = 10
pass
class Sub(User):
pass
print(User.__dict__)
{'__dict__': <attribute '__dict__' of 'User' objects>, 'x': 10, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'User' objects>, '__doc__': None}
#!/usr/bin/u/ubv/a python
# _*_ coding:utf8 _*_
class User():
x = 10
pass
class Sub(User):
pass
{'x': 10, '__module__': '__main__', '__doc__': None}
调用mro返回的是一个继承序列:
super的继承顺序严格遵循mro继承序列
多继承的情况下:从左至右
在python3中提供了一个查找新式类查找顺序的内置方法,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
print(C.mro())
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
c = C()
c.test()
from A.test
from B.test
多继承情况下造成‘钻石继承’
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()
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
from F
菱形继承下的经典类和新式类的详解:
https://blog.csdn.net/XiaoMaGe1996/article/details/80828864