zoukankan      html  css  js  c++  java
  • python之面向对象(继承的实现原理及封装)

    一、继承的实现原理

    继承的顺序

    class A(object):
        def test(self):
            print('from A')
    
    class B(A):
        def test(self):
            print('from B')
    
    class C(A):
        def test(self):
            print('from C')
    
    class D(B):
        def test(self):
            print('from D')
    
    class E(C):
        def test(self):
            print('from E')
    
    class F(D,E):
        # def test(self):
        #     print('from F')
        pass
    f1=F()
    f1.test()
    print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性
    
    #新式类继承顺序:F->D->B->E->C->A
    #经典类继承顺序:F->D->B->A->E->C
    #python3中统一都是新式类
    #pyhon2中才分新式类与经典类

    继承原理

    python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

    >>> F.mro() #等同于F.__mro__
    [<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, 
    <class 'object'>]

    子类继承了父类的方法,然后想进行修改,注意了是基于原有的基础上修改,那么就需要在子类中调用父类的方法

    方法一:父类名.父类方法()

    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    
    class Vehicle: #定义交通工具类
         Country='China'
         def __init__(self,name,speed,load,power):
             self.name=name
             self.speed=speed
             self.load=load
             self.power=power
    
         def run(self):
             print('开动啦...')
    
    class Subway(Vehicle): #地铁
        def __init__(self,name,speed,load,power,line):
            Vehicle.__init__(self,name,speed,load,power)
            self.line=line
    
        def run(self):
            print('地铁%s号线欢迎您' %self.line)
            Vehicle.run(self)
    
    line13=Subway('中国地铁','180m/s','1000人/箱','',13)
    line13.run()
    View Code

    方法二:super()

    class Vehicle: #定义交通工具类
         Country='China'
         def __init__(self,name,speed,load,power):
             self.name=name
             self.speed=speed
             self.load=load
             self.power=power
    
         def run(self):
             print('开动啦...')
    
    class Subway(Vehicle): #地铁
        def __init__(self,name,speed,load,power,line):
            #super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
            super().__init__(name,speed,load,power)
            self.line=line
    
        def run(self):
            print('地铁%s号线欢迎您' %self.line)
            super(Subway,self).run()
    
    class Mobike(Vehicle):#摩拜单车
        pass
    
    line13=Subway('中国地铁','180m/s','1000人/箱','',13)
    line13.run()
    View Code

    不用super引发的惨案

    #每个类中都继承了且重写了父类的方法
    class A:
        def __init__(self):
            print('A的构造方法')
            
    class B(A):
        def __init__(self):
            print('B的构造方法')
            A.__init__(self)
    class C(A):
        def __init__(self):
            print('C的构造方法')
            A.__init__(self)
            
    class D(B,C):
        def __init__(self):
            print('D的构造方法')
            B.__init__(self)
            C.__init__(self)
    f1=D()
    print(D.__mro__) 
    '''
    D的构造方法
    B的构造方法
    A的构造方法
    C的构造方法
    A的构造方法
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    '''
    View Code

    使用super()的结果

    class A:
        def __init__(self):
            print('A的构造方法')
    
    class B(A):
        def __init__(self):
            print('B的构造方法')
            super().__init__()    #super(B,self).__init__()
    class C(A):
        def __init__(self):
            print('C的构造方法')
            super().__init__()    #super(C,self).__init__()
    
    class D(B,C):
        def __init__(self):
            print('D的构造方法')
            super().__init__()    #super(D,self).__init__()
            # C.__init__(self)
    f1=D()
    print(D.__mro__)
    '''
    D的构造方法
    B的构造方法
    C的构造方法
    A的构造方法
    (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    '''
    View Code

    当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

    二、封装

    1、要封装什么

    封装数据和方法

    2、为什么要封装

    封装不是单纯意义的隐藏:

      1:封装数据的主要原因是:保护隐私

      2:封装方法的主要原因是:隔离复杂度

    3、封装分为两个层面

    封装其实分为两个层面,但无论哪种层面的封装,都要对外界提供好访问你内部隐藏内容的接口(接口可以理解为入口,有了这个入口,使用者无需且不能够直接访问到内部隐藏的细节,只能走接口,并且我们可以在接口的实现上附加更多的处理逻辑,从而严格控制使用者的访问。

    第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装。

    注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口

    第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

    在python中用双下划线的方式实现隐藏属性(设置成私有的)

    类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:

    class Teacher:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
    
        def tell_info(self):
            print('姓名:%s,年龄:%s' %(self.__name,self.__age))
        def set_info(self,name,age):
            if not isinstance(name,str):
                raise TypeError('姓名必须是字符串类型')
            if not isinstance(age,int):
                raise TypeError('年龄必须是整型')
            self.__name=name
            self.__age=age
    
    t=Teacher('egon',18)
    t.tell_info()
    
    t.set_info('egon',19)
    t.tell_info()

    这种自动变形的特点:

    1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

    2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

    2.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

    注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了。

    这种变形需要注意的问题是:

    1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

    2.变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形

    三、propety函数的应用

    # class Peopel:
    #     def __init__(self,name,age,sex,weight,height,permission=False):
    #         self.__name=name
    #         self.__age=age
    #         self.__sex=sex
    #         self.__height=height
    #         self.__weight=weight
    #         self.permission=permission
    #     @property
    #     def info(self):
    #         print("""
    #         -----%s info-----
    #         name:%s
    #         age:%s
    #         sex:%s
    #         weight:%s
    #         height:%s
    #         """%(self.__name,self.__name,self.__age,self.__sex,self.__height,self.__weight))
    #     @property
    #     def bmi(self):
    #         res=self.__weight / (self.__height ** 2)
    #         return res
    #     @property
    #     def name(self):
    #         return self.__name
    #     @name.setter
    #     def name(self,val):
    #         if not isinstance(val,str):
    #             raise TypeError('must be str')
    #         self.__name=val
    #     @name.deleter
    #     def name(self):
    #         if not self.permission:
    #             raise PermissionError('不让删')
    #         del self.__name
    # egon=Peopel('egon',18,'male',80,1.75)
    # egon.info
    # print(egon.bmi)
    # print(egon.name)

    property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

  • 相关阅读:
    Sample XPS Documents Download
    触发器中的inserted表和deleted表
    Using freewheel.labs.autodesk.com to auto generate preview images of DWF files on your web site
    解除SQL对组件"Ad Hoc Distributed Queries"的"STATEMENT'OpenRowset OpenDatasource"的访问
    读写xps
    XPS文件,在Windows XP下的打开查看阅读和打印方法。
    Learning to Reference Inserted and Deleted Tables
    Get value from updated, inserted and deleted
    Reinstall Microsoft Helper Viewer
    如何查找文件的IFilter
  • 原文地址:https://www.cnblogs.com/fenglinglf/p/7123052.html
Copyright © 2011-2022 走看看