• 面向对象——封装


    封装

    将具体、复杂的细节封装在一起。

    1. 如何将属性隐藏

    如果想让属性或方法隐藏,在其前加 ‘__’ 双下划线,python就将其视为私有。
    注意:
    (1). 私有变量是在定义时生成的。
    (2). python没有实现绝对的私有,而是在定义时将私有属性解析 ‘_类名__属性’,(单下划线类名双下划线属性)

    #其实这仅仅这是一种变形操作
    #类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式:
    
    class A:
        __x = 1  #定义时被解释为 _A__x
    
        def __init__(self, name):
            self.__name = name # 定义时被解释为 self._A__name
    
        def __foo(self): #定义时被解释为 _A__foo
            print('run foo')
        def bar(self):
            self.__foo() #只有在类内部才可以通过__foo的形式访问到.
            
    # 外部无法通过‘类名.属性’的方式访问
    # print(A.__x) AttributeError: type object 'A' has no attribute '__x'
    
    a = A('yk')
    print(a.__dict__)  # {'_A__name': 'yk'}
    print(_A__name)  # yk 可以通过_类名__x的形式访问

    特点:
    1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
    2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
    3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

    问题:
    1、这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N。
    2、变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形

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

    #正常情况
    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() #只会与自己所在的类为准,即调用self._A__fa
    
    class B(A):
        def __fa(self):
            print('from B')
    
    b=B()
    b.test() # from A

    2. 封装不是单纯意义的隐藏

    # 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):
            # 添加自己的控制逻辑
            if not isinstance(name, str):
                raise TypeError('姓名必须是字符串类型')
            if not isinstance(age, int):
                raise TypeError('年龄必须是整型')
            self.__name = name
            self.__age = age
            
    p = People('yk',18)
    p.tell_info() # yk,年龄:18
    p.set_info('小明',15)
    p.tell_info() # 小明,年龄:15
    p.set_info('小花','14') # 报错 TypeError: 年龄必须是整型
    # 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()
  • 相关阅读:
    让程序的性能提升10倍
    以正确的姿势实现一棵JavaScript菜单树
    利用php数组函数进行函数式编程
    yum安装下的nginx,如何添加模块,和添加第三方模块
    前端面试题 vue
    前端常用面试题目及答案-HTML&CSS篇
    使用after伪类,配合IE的zoom或者overflow清除浮动
    函数式编程
    在CentOS 7上安装Node.js
    node中__dirname、__filename、process.cwd()、process.chdir()表示的路径
  • 原文地址:https://www.cnblogs.com/ykgo/p/9356338.html
Copyright © 2020-2023  润新知