zoukankan      html  css  js  c++  java
  • 面向对象之继承与派生,属性查找

    目录:

        继承

        派生

        属性查找

        练习

    继承:单/多

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

  • 相关阅读:
    POJ 2991 Crane(线段树)
    HDU 1754 I Hate It(线段树)
    HDU 1754 I Hate It(线段树)
    HDU 1166 敌兵布阵 (线段树模版题)
    HDU 1166 敌兵布阵 (线段树模版题)
    Tree Recovery
    Tree Recovery
    情人节的电灯泡(二维树状数组)
    情人节的电灯泡(二维树状数组)
    【LeetCode】Validate Binary Search Tree 二叉查找树的推断
  • 原文地址:https://www.cnblogs.com/xuechengeng/p/9838263.html
Copyright © 2011-2022 走看看