一,继承的介绍
1,什么是继承
继承一种新建类方式,新建的类称之为子类/派生类,被继承的类称之为父类\基类\超类
python中继承的特点:
1,子类可以遗传/重用父类的属性
2,python中一个子类可以同时继承多个父类
3,在继承背景下去说,python中的类分为两种:新式类和经典类
新式类:但凡继承了object的类foo,以及该类的子集.....都是新式类
在python3中一个类即便是没有显示的继承任何类,默认就会继承object
即在python3中所有的类都是新式类
经典类:没有继承object的类,以及该类的子集......都是经典类
在python2中才区分新式类和经典类
在python中一个类如果没有显示地继承任何类,也不会继承object
2,为何要用继承
减少类与类之间代码冗余
3,如何用继承
class Parent1(object):
pass
class Parent2(object):
pass
class Sub1(object):
pass
class Sub2(Parent1,Parent2):
pass
print(Parent1.__bases__)
print(Parent2.__base__)
print(Sub1.__base__)
print(Sub2.__base__)
输出是:
(<class 'object'>,)
(<class 'object'>,)
(<class '__main__.Parent1'>,)
(<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 OldboyStudent(OldboyPeople)
def choose_course(self):
print("%s choosing course" %self.name)
class OldboyTeacher(OldboyPeople):
def score(self,stu,num):
stu.score = num
stu1 = OldboyStudent('老王',38,'male')
print(stu1.__dict__)
tea1 = OldboyTeacher('张老师',25,'female')
print(tea1.__dict__)
输出是:
{'name': '老王', 'age': 38, 'sex': 'male'}
{'name': '张老师', 'age': 25, 'sex': 'female'}
可以直接调用父类里面的__init_函数给学生和老师对象传值
可是,这样对象就不能有独特的特征,所以要在子集下面再定义一个__init__函数
三,在子类派生的新方法中重用父类功能的方式一
指名道姓的引用某一类中的函数
总结:
1,与继承无关
2,访问时类的函数,没有自动传值的效果
class OldboyPeople:
school = 'Oldboy'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople)
def __init__(self,name,age,sex,score = 0):
OldboyPeople.__init__(self,name,age,sex)
self.score = score
def choose_course(self):
print("%s choosing course" %self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,sex,level):
OldboyPeople.__init__(self,name,age,sex)
self.level = level
def score(self,stu,num):
stu.score = num
stu1 = OldboyStudent('老王',38,'male',80)
print(stu1.__dict__)
tea1 = OldboyTeacher('张老师',25,'famale',10)
print(tea1__dict__)
{'name': '老王', 'age': 38, 'sex': 'male', 'score': 80}
{'name': '张老师', 'age': 25, 'sex': 'female', 'level': 10}
总结,这样可以直接调用父类的函数,和继承无关也按照类名可以直接查找
四,在单继承背景下的属性查找
1,查找的优先级:对象>>对象的类>>父类>>父类
class Foo():
x = 4 #第四查找
class Bar1(Foo):
x = 3 #第三查找
class Bar2(Bar1):
x = 2 # 第二查找
obj = Bar2()
obj.x = 1 # 第一查找
print(obj.x)
例题:
class Foo:
def f1(self):
print('Foo.f1')
def f1(self):
print('Foo.f2')
self.f1()
class Bar(Foo):
def f1(self):
print('Bar.f1')
obj = Bar()
obj.f2()
输出为:
Foo.f2
Bar.f1
它只要遇到self查值都会按照:对象>>对象的类>>父类>>父类顺序查找
五,在多继承背景下的属性查找
1,优先级:如果一个子类继承多个分支(多个分支没有共同继承一个非object的类)
此时属性的查找优先级是:对象>>对象的类>>按照从左往右的顺序一个分支一个分支的找下去
2,菱形的继承问题:
新式类:广度有限查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类
经典类:深度有限查找,从左往右一个分支有个分支的查找,在第一个分支就查找顶级类
第四层:
class G:
x = 'G'
第三层:
class E(G):
x = 'E'
class F:
x = 'F'
第二层:
class B(E):
x = 'B'
class C(F):
x = 'C'
class D:
x = 'D'
第一层:
class A(B,C,D):
x = 'A'
obj = A()
obj.x = 1
print(obj.x)
新式类(广度优先):obj>>A>>B>>E>>C>>F>>D>>G>>object
经典类(深度优先):obj>>A>>B>>E>>G>>C>>F>>D
python专门为新式类内置了一个mro的方法,用来查看c3算法的计算结果,
print(A.mro()) # 也就是新式类查找名称的顺序
六,在子类派生的新方法中重用父类功能的方式二:
super()必须在类中用
1,在python2中:supper(自己的类名,自己的对象)
2,在python3中:supper()
调用函数会得到一个特殊的对象,应该专门用来访问父类中的属性,强调的是:完全参照mro列表!!!
总结:
1,严格依赖继承的mro列表
2,访问是绑定方法,有自动传值的效果
class OldboyPeople:
school = 'Oldboy'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
class OldboyStudent(OldboyPeople):
def __init__(self, name, age, sex, score=0):
super(OldboyStudent,self).__init__(name,age,sex) # supper在python2中的用法
self.score = score
def choose_course(self):
print('%s choosing course' % self.name)
class OldboyTeacher(OldboyPeople):
def __init__(self,name,age,sex,level):
super().__init__(name,age,sex) # supper在python3中的用法
self.level=level
def score(self,stu,num):
stu.score=num
stu1=OldboyStudent("老王"'',38,'male')
print(stu1.__dict__)
tea1=OldboyTeacher('张老师',25,'female',10)
print(tea1.__dict__)
输出是:
{'name': '老王', 'age': 38, 'sex': 'male', 'score': 0}
{'name': '张老师', 'age': 25, 'sex': 'female', 'level': 10}