zoukankan      html  css  js  c++  java
  • 面向对象【林老师版】:封装-如何隐藏?(十四)

    一、引子

    从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,还有alex一起装进麻袋,然后把麻袋封上口子。照这种逻辑看,封装=‘隐藏’,这种理解是相当片面的

    在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

    1、代码

    class A:
        __x=1 #_A__x=1
    
        def __init__(self,name):
            self.__name=name #self._A__name=name
    
        def __foo(self): #def _A__foo(self):
            print('run foo')
    
    
    print(A.__dict__)
    

    二、自动变形的特点

    1、这仅仅这是一种变形操作

    1、代码

    print(A.__dict__)

    2、打印输出

    {'__module__': '__main__', '_A__x': 1, '__dict__': <attribute '__dict__' of 'A' objects>, '__init__': <function A.__init__ at 0x0000000000B92378>, '__doc__': None, '_A__foo': <function A.__foo at 0x0000000000B92400>, '__weakref__': <attribute '__weakref__' of 'A' objects>}
    
    类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式

    2、在类内部是可以直接使用:obj.__AttrName

     1、代码

    
    
    a=A('egon')
    print(a.__dict__)
    
    
    

    2、打印结果

    
    
    {'_A__name': 'egon'}
    
    
    
    类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。

    3、在类外部无法直接obj.__AttrName

    1、打印类的属性代码

    1、代码

    print(A.__x)
    

    2、打印输出

    Traceback (most recent call last):
      File "F:/s13/day07/17 如何实现属性的隐藏.py", line 11, in <module>
        print(A.__x)
    AttributeError: type object 'A' has no attribute '__x'
    

    2、打印对象的属性

    1、代码

    print(A.__foo)
    

    2、打印输出结果

    Traceback (most recent call last):
      File "F:/s13/day07/17 如何实现属性的隐藏.py", line 12, in <module>
        print(A.__foo)
    AttributeError: type object 'A' has no attribute '__foo'
    

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

    4、子类无法覆盖父类__开头的属性

    1、代码

        def bar(self):
            self.__foo() #self._A__foo()
            print('from bar')
    
    a=A('egon')
    a.bar()
    

    2、输出结果

    run foo
    from bar
    

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

    1、代码

    a=A('egon')
    a._A__foo()
    a._A__x
    
    #print(a.__name) #a.__dict__['__name']
    print(a.__dict__)
    

    2、打印输出结果

    run foo
    {'_A__name': 'egon'}

    5、最终总结注释

    #其实这仅仅这是一种变形操作
    #类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
    
    class A:
        __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
        def __init__(self):
            self.__X=10 #变形为self._A__X
        def __foo(self): #变形为_A__foo
            print('from A')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.
    
    #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

    三、变形需要注意的问题

    1、外部直接访问属性

    1、代码

    class Foo:
        def __func(self): #_Foo__func
            print('from foo')
    
    class Bar(Foo):
        def __func(self): #_Bar__func
            print('from bar')
    
    
    class B:
        __x=1
    
        def __init__(self,name):
            self.__name=name #self._B__name=name
    
    
    print(B._B__x)
    

    2、打印输出

    1
    

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

    2、变形的过程只在类的定义时发生一次

    1、代码

    B.__y=2
    print(B.__dict__)
    b=B('egon')
    print(b.__dict__)
    
    b.__age=18
    print(b.__dict__)
    print(b.__age)

    2、打印输出

    {'__module__': '__main__', '__y': 2, '__doc__': None, '_B__x': 1, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__init__': <function B.__init__ at 0x0000000000A62488>}
    {'_B__name': 'egon'}
    {'_B__name': 'egon', '__age': 18}
    18
    

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

     3、在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

    1、代码

    class A:
        def foo(self):
            print('A.foo')
    
        def bar(self):
            print('A.bar')
            self.foo() #b.foo()
    
    class B(A):
        def foo(self):
            print('B.foo')
    
    b=B()
    b.bar()
    

    2、打印输出

    A.bar
    B.foo

    3、带注释的

    class A:
        def __foo(self): #在定义时就变形为_A__foo
            print('A.foo')
    
        def bar(self):
            print('A.bar')
            self.__foo() #只会与自己所在的类为准,即调用_A__foo
    
    class B(A):
        def __foo(self): #_B__foo
            print('B.foo')
  • 相关阅读:
    cinder支持nfs快照
    浏览器输入URL到返回页面的全过程
    按需制作最小的本地yum源
    创建可执行bin安装文件
    RPCVersionCapError: Requested message version, 4.17 is incompatible. It needs to be equal in major version and less than or equal in minor version as the specified version cap 4.11.
    惠普IPMI登陆不上
    Linux进程状态——top,ps中看到进程状态D,S,Z的含义
    openstack-neutron基本的网络类型以及分析
    openstack octavia的实现与分析(二)原理,架构与基本流程
    flask上下文流程图
  • 原文地址:https://www.cnblogs.com/luoahong/p/9927702.html
Copyright © 2011-2022 走看看