zoukankan      html  css  js  c++  java
  • 面向对象:抽象类,继承的实现原理,封装

    抽象类:

    本身不能被实例化,也不应该被实例化,他的作用就是定义标准,不用具体的实现

    继承的实现原理:

    注:新式类可以使用print(<class_name>.mro())来查询,经典类无法使用

    如下继承关系

    根据上图代码示例:
    class A:
        def test(self):
            print('from A')
        pass
    class B(A):
        def test(self):
            print('from B')
        pass
    class C:
        def test(self):
            print('from C')
        pass
    class D:
        def test(self):
            print('from D')
        pass
    class E(B,C,D):
        def test(self):
            print('from E')
        pass
    
    e = E()
    e.test()
    
    执行结果:
    默认这样执行,会显示"from E" ,因为调用一个方法会,先从自己的类中查询,下面我们依次注释掉下列类的test:
    把E类的test注释掉:结果显示"from B" ,
    把B类的test注释掉:结果显示"from A" ,
    把A类的test注释掉:结果显示"from C" ,
    把C类的test注释掉:结果显示"from D" ,
    把D类的test注释掉:结果显示"'E' object has no attribute 'test'"
    根据上面的结果过程:在Python3中,当继承多个父类时且父类没有共同的父类时,这时属性的查询顺序是(深度优先)
    上面的属性查询顺序总结:E-->B-->A-->C-->D
    这个可能不是很有说服力,那么我们在新建一个F类,让C类继承F类,这时属性的查询顺序如下(仅列出结果):
    属性查询顺序:E-->B-->A-->C-->F-->D
    

      

    如果继承多个附类且父类有共同的父类时:

    根据上图代码示例:
    class A:
        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:
        def test(self):
            print('from D')
        pass
    class E(B,C,D):
        def test(self):
            print('from E')
        pass
    
    e = E()
    e.test()
    
    执行结果:
    默认执行:显示"from E"
    把E类的test注释掉:结果显示"from B"
    把B类的test注释掉:结果显示"from C"
    把C类的test注释掉:结果显示"from A"
    把A类的test注释掉:结果显示"from D"
    把D类的test注释掉:结果显示"'E' object has no attribute 'test'"
    根据上面测试的结果:得出结论在Python3中,当继承多个父类且父类还有共同的父类时,这时属性查找是(广度优先)
    上面的属性查找顺序总结:E-->B-->C-->A-->D
    

      

    注:在Python2中因为分新式类和经典类的区别,所以跟Python3有些许不同。

    如下图在Python2中:

      新式类:同Python3中一样,是广度优先。所以属性查找顺序是:E-->B-->C-->A-->D

      经典类:和新式类恰恰相反,是深度优先。所以属性查找顺序是:E-->B-->A-->C-->D

    子类调用父类的方法:

    super():内置函数,使用绑定方法调用父类的方法。(仅支持新式类)

    注:在Python2中需要写成:super(S1,self).__init__(name,age)   #S1 为子类的名字。

    class Parent:
        def __init__(self,name,age):
            self.name = name
            self.age = age
    
    class D:
        def walk(self):
            return ('from D')
    
    class S1(Parent,D):
        def __init__(self,name,age,job,school):
            super().__init__(name,age)   #因为使用绑定方法调用父类的方法,所以不需要传递self
            self.job = job
            self.school = school
            super().walk()
    t = S1('egon',73,'teach','oldboy')
    
    print(t.name,t.age,t.walk())
    
    执行结果:
    D:PythonPython36-32python.exe E:/Python/DAY-20/day20.py
    egon 73 from D
    
    Process finished with exit code 0
    

      

    封装:

      注:Python中没有真正的隐藏,仅仅是语法上做了些操作。

      方法:

        在想要封装的变量或者函数名前加上"__"两个下划线,就可以。

        加上两个下划线之后,只有在类的定义阶段或者对象的定义阶段(实例化)发生。且在类的外部无法直接调用,但是在类的内部可以直接调用(在定义时全部变形了)

        封装其实就是变形。

    正常的状态:(注意观察下列红色标识)
    class A:
        def foo(self):
            print('from A foo')
            self.bar()
        def bar(self):
            print('from A bar')
    class B(A):
        def bar(self):
            print('from B bar')
    b = B()
    print(A.__dict__)  
    b.foo()    #正常状态调用 .foo(),因为A是B的父类,B类中没有foo所以向上查找,在A中找到并执行,foo有个self.bar,self指的对象所以可以认为是在执行b.bar() 又搜寻一次父类,在B中找到,所以结果显示from B bar
     
    执行结果:
    D:PythonPython36-32python.exe E:/Python/DAY-20/day20.py
    {'__module__': '__main__', 'foo': <function A.foo at 0x03873930>, 'bar': <function A.bar at 0x038738E8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
    from A foo
    from B bar
    
    Process finished with exit code 0
    
    隐藏变形:
    class A:
        def foo(self):
            print('from A foo')
            self.__bar()     #做了隐藏,这时在执行找到就不是bar了,而是 _A__bar,下面的结果能看出来名字被变形了
        def __bar(self):    #这里等于   _A__bar(self)   所以最后显示  from A bar
            print('from A bar')
    class B(A):
        def bar(self):
            print('from B bar')
    b = B()
    print(A.__dict__)
    b.foo()
    
    执行结果:
    D:PythonPython36-32python.exe E:/Python/DAY-20/day20.py
    {'__module__': '__main__', 'foo': <function A.foo at 0x03693930>, '_A__bar': <function A.__bar at 0x036938E8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
    from A foo
    from A bar
    
    Process finished with exit code 0
    

      

    一个封装的例子

    class User:
        def __init__(self,name,age,sex):   #这里能看到隐藏了所有的用户信息
            self.__name = name
            self.__age = age
            self.__sex =sex
    
        def modify_name(self,val):   #定义更改用户名的接口
            if not isinstance(val,str):   #判断是否是字符串
                raise TypeError('must be str')   #如果不是字符串则主动抛出异常
            self.__name = val   #如果是字符串则执行这条,重新赋值
    
        def dis_info(self):   #显示用户信息
            print('''
            Name:%s
            Age:%s
            Sex:%s
            '''%(self.__name,self.__age,self.__sex))
    t = User('laochai',73,'male')   #传入参数 用户名为 laochai
    t.modify_name('abc')   #更改用户名 abc
    t.dis_info()   #打印信息
    
    执行结果:
    D:PythonPython36-32python.exe E:/Python/DAY-20/day20.py
    
            Name:abc
            Age:73
            Sex:male
            
    
    Process finished with exit code 0
    

       Property:内置函数,一个装饰器,功能是自动执行函数,可以在封装中起到去括号的目的,让用户不知道自己被套路了。

    class User:
        def __init__(self,name,age,sex):
            self.__name = name
            self.__age = age
            self.__sex =sex
    
        @property    #加上property装饰name
        def name(self):
            print(self.__name)
    
        @name.setter  #调用 .setter方法
        def name(self,val):
            self.__name = val   #修改用户名
    
        @property  #调用property装饰
        def dis_info(self):
            print('''
            Name:%s
            Age:%s
            Sex:%s
            '''%(self.__name,self.__age,self.__sex))
    t = User('egon',18,'male')
    t.name = 'abc'   #直接修改用户名
    t.dis_info   #查看信息时没有加()执行
    
    执行结果:
    D:PythonPython36-32python.exe E:/Python/DAY-20/day20.py
    
            Name:abc
            Age:18
            Sex:male
            
    
    Process finished with exit code 0
    

      

  • 相关阅读:
    Debate
    图形算法
    OpenGL Notes
    How to Write an Ethics Paper
    Thesis
    addWindowListener -> WindowAdapter -> windowClosing
    Thesis
    Bootcamp: An error occurred while partitioning the disk
    What Is XML Schema
    What Is XML
  • 原文地址:https://www.cnblogs.com/yuxiang-qiwa/p/7894337.html
Copyright © 2011-2022 走看看