zoukankan      html  css  js  c++  java
  • 类的封装

    从封装本身的意思去理解,封装就好像是拿来一个麻袋,把小猫,小狗,小王八,还有egon一起装进麻袋,然后把麻袋封上口子。但其实这种理解相当片面

    一、封装什么

    • 你钱包的有多少钱(数据的封装)

    • 你的性取向(数据的封装)

    • 你撒尿的具体功能是怎么实现的(方法的封装)

    二、为什么要封装

    封装数据的主要原因是:保护隐私(作为男人的你,脸上就写着:我喜欢男人,你害怕么?)

    封装方法的主要原因是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了,比如你不必知道你自己的尿是怎么流出来的,你直接掏出自己的接口就能用尿这个功能)

    提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),就是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。

    三、两个层面的封装

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

    3.1 第一个层面

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

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

    3.2 第二个层面

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

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

    类中所有双下划线开头的名称如__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的形式访问到.
    

    这种自动变形的特点:

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

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

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

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

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

    1. 这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
    # 对象测试
    a = A()
    print(a._A__N)
    
    0
    
    # 对象测试
    print(a._A__X)
    
    10
    
    # 类测试
    print(A._A__N)
    
    0
    
    # 类测试
    try:
        print(A._A__X)  # 对象私有的属性
    except Exception as e:
        print(e)
    
    type object 'A' has no attribute '_A__X'
    
    1. 变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
    a = A()
    print(a.__dict__)
    
    {'_A__X': 10}
    
    a.__Y = 1
    
    print(a.__dict__)
    
    {'_A__X': 10, '__Y': 1}
    
    1. 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
    # 正常情况
    class A:
        def fa(self):
            print('from A')
    
        def test(self):
            self.fa()
    
    
    class B(A):
        def fa(self):
            print('from B')
    
    
    b = B()
    b.test()
    
    from B
    
    # 把fa定义成私有的,即__fa
    class A:
        def __fa(self):  # 在定义时就变形为_A__fa
            print('from A')
    
        def test(self):
            self.__fa()  # 只会与自己所在的类为准,即调用_A__fa
    
    
    class B(A):
        def __fa(self):
            print('from B')
    
    
    b = B()
    b.test()
    
    from A
    

    四、私有模块

    python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果模块中的变量名_private_module以单下划线开头,那么from module import *时不能被导入该变量,但是你from module import _private_module依然是可以导入该变量的

    其实很多时候你去调用一个模块的功能时会遇到单下划线开头的(socket._socket,sys._home,sys._clear_type_cache),这些都是私有的,原则上是供内部调用的,作为外部的你,一意孤行也是可以用的,只不过显得稍微傻逼一点点

    python要想与其他编程语言一样,严格控制属性的访问权限,只能借助内置方法如__getattr__,详见面向对象高级部分。

    五、练习

    • 多态是在定义角度

    • 多态性是在调用角度(使用角度)

    class A:
        def fa(self):
            print('from A')
    
        def test(self):
            self.fa()
    
    
    class B(A):
        def fa(self):
            print('from B')
    
    
    b = B()
    b.test()
    
    from B
    
    class A:
        def __fa(self):
            print('from A')
    
        def test(self):
            self.__fa()
    
    
    class B(A):
        def __fa(self):
            print('from B')
    
    
    b = B()
    b.test()
    
    from A
    

    注:__名字,这种语法只在定义的时候才有变形的效果,如果类或对象已经产生了,就不会有变形的效果了。

  • 相关阅读:
    UVA 11174 Stand in a Line,UVA 1436 Counting heaps —— (组合数的好题)
    UVA 1393 Highways,UVA 12075 Counting Triangles —— (组合数,dp)
    【Same Tree】cpp
    【Recover Binary Search Tree】cpp
    【Binary Tree Zigzag Level Order Traversal】cpp
    【Binary Tree Level Order Traversal II 】cpp
    【Binary Tree Level Order Traversal】cpp
    【Binary Tree Post order Traversal】cpp
    【Binary Tree Inorder Traversal】cpp
    【Binary Tree Preorder Traversal】cpp
  • 原文地址:https://www.cnblogs.com/nickchen121/p/10989430.html
Copyright © 2011-2022 走看看