面向对象之继承与派生,属性查找
目录:
继承:单/多
类和对象本质上是名称空间
python2与python3在继承上的区别:
新式类:但凡继承object类的子类,以及该子类的子子类,...都称之为新式类
经典类:没有继承object类的子类,以及该子类的子子类,...都称之为经典类
只有在python2中才区分新式类与经典类,但是开发中基本都是新式类,在python2中也会继承object类
1. 什么是继承? 在程序中继承是一种新建子类的方式,新创建的类称之为子类\派生类,被继承的类称之为父类\基类\超类 继承描述的是一种遗传关系,子类可以重用父类的属性 2. 为何用继承? 减少类与类之间代码冗余的问题 3. 如何继承 先抽象再继承
执行原理:
class Base(object): def __init__(self,name): self.name = name print(name) self.Testfunc() def Testfunc(self): print ('do Base Testfunc') class Son(Base): def Testfunc(self): print ('do Son Testfunc') sonobj = Son('sonobj') # 子类实例化过程中要执行__init__方法,子类没有,去父类找; # 在父类的__init__方法传入实例化的参数name,和子类对象,所有self.Testfunc()是执行子类方法
代码:
class Parent1(object): pass class Parent2: pass class Sub1(Parent1): pass class Sub2(Parent1,Parent2): pass print(Sub1.__bases__)#列出其基类,(<class '__main__.Parent1'>,) print(Sub2.__bases__)#(<class '__main__.Parent1'>, <class '__main__.Parent2'>) print(Parent1.__bases__)#(<class 'object'>,) print(Parent2.__bases__)#(<class 'object'>,)
对象的属性只会在自身及类名称空间找,不会去全局变量找:
x=2 class Foo: x=1 pass obj=Foo() obj.x=3 print(obj.x)#3 x=2 class Foo: x=1 pass obj=Foo() #obj.x=3 print(obj.x)#1 x=2 class Foo: #x=1 pass obj=Foo() #obj.x=3 print(obj.x)#报错, 'Foo' object has no attribute 'x'
在子类派生出的新功能中重用父类的功能:
方式一: 指名道姓地访问某一个类中的函数,与继承无关,要严格传值,包括self:
1 class OldboyPeople: 2 school = 'Oldboy' 3 def __init__(self, name, age, gender): 4 self.name = name 5 self.age = age 6 self.gender = gender 7 8 # print(OldboyPeople.__init__) 9 10 class OldboyStudent(OldboyPeople): 11 # def __init__(self, name, age, gender): 12 # self.name = name 13 # self.age = age 14 # self.gender = gender 15 #继承了父类中的__init__函数,减少了代码冗余 16 def choose_course(self):#选课行为 17 print('%s is choosing course' %self.name) 18 19 class OldboyTeacher(OldboyPeople): 20 # tea, 'egon', 18, 'male', 10, 3000 21 def __init__(self, name, age, gender,level,salary):#老师类有特有的属性 22 # self.name = name 23 # self.age = age 24 # self.gender = gender 25 OldboyPeople.__init__(self, name, age, gender)#通过类名访问函数,严格按照函数传值(值为上层__init__函数传入的参数),减少了代码冗余 27 self.level=level 28 self.salary=salary 29 30 def score(self,stu,num):#打分行为 31 stu.num=num 32 print('老师%s给学生%s打分%s' %(self.name,stu.name,num))
tea=OldboyTeacher('egon',18,'male',10,3000) #相当于__init___(tea,'egon',18,'male',10,3000)
print(tea.__dict__)#{'name': 'egon', 'age': 18, 'gender': 'male', 'level': 10, 'salary': 3000}
方式二: super(OldboyTeacher,self),在python3中super()可以不传参数,调用该函数不用传第一个self,会得到一个特殊的对象,该对象是专门用来访问父类中属性
强调:super会严格参照类的mro列表依次查找属性
class OldboyPeople: school = 'Oldboy' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class OldboyTeacher(OldboyPeople): # tea, 'egon', 18, 'male', 10, 3000 def __init__(self, name, age, gender,level,salary): #OldboyPeople.__init__(self, name, age, gender) #super(OldboyTeacher,self).__init__(name, age, gender) super().__init__(name,age,gender) self.level=level self.salary=salary def score(self,stu,num): stu.num=num print('老师%s给学生%s打分%s' %(self.name,stu.name,num)) tea=OldboyTeacher('egon',18,'male',10,3000) #__init___(tea,'egon',18,'male',10,3000) print(tea.__dict__)#{'name': 'egon', 'age': 18, 'gender': 'male', 'level': 10, 'salary': 3000}
#顺序
1 #A没有继承B, 2 class A: 3 def test(self): 4 print('A.test') 5 super().test()#没有父类,不执行 6 class B: 7 def test(self): 8 print('from B') 9 class C(A,B): 10 pass 11 12 c=C() 13 c.test()#A.test #from B 14 print(C.mro())#[<class'main.C'>,<class'main.A'>,<class'main.B'>,<class'object'>]
属性查找:
在单继承背景下,无论是新式类还是经典类属性查找顺序都一样:先obj->类->父类->...
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() #obj.f1(),不会就近查找,会先从obj对象所在的类查找的 class Bar(Foo): def f1(self): print('Bar.f1') obj=Bar() obj.f2() #Foo.f2 #Bar.f1
如果一个子类继承多个分支,但多个分支没有汇聚到一个非object类,无论是新式类还是经典类属性查找顺序都一样:会按照从左到右的顺序一个分支一个分支的查找下去
class E: xxx='E' pass class F: # xxx='F' pass class B(E): # xxx='B' pass class C(F): xxx='C' pass class D: # xxx='D' pass class A(B,C,D): # xxx='A' pass obj=A() print(obj.xxx)#E print(A.mro())#查找属性顺序:A->B->E->C->F->D->object
如果一个子类继承多个分支,但是多个分支最终汇聚到一个非object类(菱形继承问题)
新式类:广度优先查找:obj->A->B->E->C->F->D->G->object
经典类:深度优先查找:obj->A->B->E->G->C->F->D
class G: xxx='G' class E(G): xxx='E' pass class F(G): xxx='F' pass class B(E): xxx='B' pass class C(F): xxx='C' pass class D(G): xxx='D' pass class A(B,C,D): xxx='A' pass print(A.mro())#查找顺序:obj->A->B->E->C->F->D->G->object
练习:
1 class A(object): 2 def __init__(self): 3 print('A') 4 super(A, self).__init__() 5 class B(object): 6 def __init__(self): 7 print('B') 8 super(B, self).__init__() 9 class C(A): 10 def __init__(self): 11 print('C') 12 super(C, self).__init__() 13 class D(A): 14 def __init__(self): 15 print('D') 16 super(D, self).__init__() 17 class E(B, C): 18 def __init__(self): 19 print('E') 20 super(E, self).__init__() 21 class F(C, B, D): 22 def __init__(self): 23 print('F') 24 super(F, self).__init__() 25 class G(D, B): 26 def __init__(self): 27 print('G') 28 super(G, self).__init__() 29 if __name__ == '__main__': 30 g = G()#G,D,A,B 31 f = F()#F,C,B,D,A,要注意,菱形问题,以及F类的继承顺序
继承图:object可以不画