• 5 [面向对象]-三大特性:封装


    1、引子

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

    先看如何隐藏

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

    class A:
        __x = 100       # 类的私有数据属性
        y = 200
        def __init__(self, name):
            self.__name = name      # 对象的私有属性
    
        def __foo(self):    # 类的私有方法
            print('run foo')
    print(A.y)
    # print(A.__x)  # 私有数据属性  # '_A__x': 100,
    # print(A.__foo)   # {'_A__foo': <function A.__foo at 0x01FC17C8>,
    
    print(A.__dict__)
    print(A._A__x)
    print(A._A__foo)
    
    
    a = A('alex')
    print(a.__dict__)
    # print(a.__name)  # {'_A__name': 'alex'}
    print(a._A__name)
    ### 运行结果
    200
    {'__weakref__': <attribute '__weakref__' of 'A' objects>, '__module__': '__main__', '__init__': <function A.__init__ at 0x01F21738>, '_A__x': 100, '_A__foo': <function A.__foo at 0x01F217C8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__doc__': None, 'y': 200}
    100
    <function A.__foo at 0x01F217C8>
    {'_A__name': 'alex'}
    alex
    

      

    2、私有属性,方法的实质

    #其实这仅仅这是一种变形操作
    #类中所有双下划线开头的名称如__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是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形

    3、特点

    class A:
        __x = 100       # 类的私有数据属性
        y = 200
        def __init__(self, name):
            self.__name = name      # 对象的私有属性
    
        def __foo(self):    # 类的私有方法
            print('run foo')
    
        def bar(self):          # 内部可以调用私有属性,方法
            self.__foo()   # self._A__foo
            print(self.__name)
            print(A.__x)
    
    a = A('alex')
    a.bar()
    ## 运行结果
    run foo
    alex
    100
    

    (2)子类无法覆盖父类的__开头的属性,方法

    class Foo:
        def func(self):  # _Foo_func
            print('run foo')
    
    class Bar(Foo):
        def func(self):   # _Bar_func
            print('new from bar')
    
    b = Bar()
    b.func()    # 子类覆盖了父类的方法
    • 外部不可以调用私有属性,方法
    class Foo:
        def __func(self):  # _Foo_func
            print('run foo')
    
    class Bar(Foo):
        def __func(self):   # _Bar_func
            print('new from bar')
    
    b = Bar()
    b.func()    # 子类覆盖了父类的方法
    

      

    4、注意的问题

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

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

        

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

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

     

     5、封装的意义

       1).封装数据属性,明确的区分内外

    class People:
        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):
            self.__name = name
            self.__age = age
    
    
    p = People('alex', 14)
    # print(p.__name)
    p.tell_info()
    
    p.set_info('jack', 33)
    p.tell_info()
    

      

    将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制

    class People:
        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):
                print('名字必须是字符串类型')
                return
            if not isinstance(age, int):
                print('年龄必须是数字类型')
                return
            self.__name = name
            self.__age = age
    
    
    p = People('alex', 14)
    # print(p.__name)
    p.tell_info()
    
    p.set_info(11, '33')
    p.tell_info()

      2):封装方法:目的是隔离复杂度

    #取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
    #对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
    #隔离了复杂度,同时也提升了安全性
    
    class ATM:
        def __card(self):
            print('插卡')
        def __auth(self):
            print('用户认证')
        def __input(self):
            print('输入取款金额')
        def __print_bill(self):
            print('打印账单')
        def __take_money(self):
            print('取款')
    
        def withdraw(self):
            self.__card()
            self.__auth()
            self.__input()
            self.__print_bill()
            self.__take_money()
    
    a=ATM()
    a.withdraw()

    6、封装与扩展性

    class Room:
        def __init__(self, name, owner, weight, length):
            self.name = name
            self.owner = owner
            self.__weight = weight
            self.__length = length
    
        def tell_area(self):
            return self.__weight * self.__length
    
    r = Room('卫生间', 'alex', 80, 80)
    
    print(r.tell_area())

  • 相关阅读:
    MRC下多个对象的内存管理
    MacOS安装flutter(MacOS下flutter环境配置)
    swift 简化使用UserDefaults,UserDefaults使用优化
    swift中多继承的实现
    iOS blowfish加密解密
    *** Assertion failure in void UIViewReportBrokenSuperviewChain(UIView *__strong, UIView *__strong, BOOL)()
    iOS建立自己cocoaPods库
    iOS关于UISwitch按钮值的改变无法监听到的问题
    iOS 11 UICollectionView顶部出现白色间隔的问题
    iOS 对UIAlertController内的输入框进行输入监听,实时改变确定、取消按钮颜色
  • 原文地址:https://www.cnblogs.com/venicid/p/8614579.html
Copyright © 2020-2023  润新知