面向对象之继承与派生,属性查找

目录:

    继承

    派生

    属性查找

    练习

继承:单/多

类和对象本质上是名称空间
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可以不画

 

posted @ 2018-10-23 18:10  ChuckXue  阅读(281)  评论(0编辑  收藏  举报