zoukankan      html  css  js  c++  java
  • 封装

    封装

    将复杂的丑陋的,隐私的细节 隐藏到内部,对外提供简单的使用接口

    对外部隐藏了内部实现的细节,并提供访问接口

    封装的目的

    1.为了保证关键数据的安全性

    2.对外部隐藏内部实现细节,隔离复杂度

    什么时候需要封装

    当数据不希望外界可以直接修改时

    当有一些数据不希望给外界使用时

    封装语法

    初始化阶段,在被封装属性前加__ 如:self.__属性

    class Person:
        def __init__(self, name, age, id_num):
            self.name = name
            self.age = age
            self.__id_num = id_num  # 被封装隐藏
        def check_id(self):  # 给外界提供访问封装属性的接口
            self.__id_num = 222  # 内部修改
            print(self.__id_num)
    p = Person('xx', 20, 110110110)
    print(p.__id_num)  # 报错 被隐藏,外界无法查看
    p.id_num = 333  # 这是在对象名称空间中创建了一个变量
    print(p.id_num)  # 打印的是对象名称空间中的变量
    p.__id_num = 555  # 这是在对象名称空间中创建了一个变量
    print(p.__id_num)  # 打印的是对象名称空间中的变量
    p.check_id()  # 外部通过接口访问

    被封装的内容的特点:

    1.外界(类外部)不能直接访问 (对象.属性名)

    2.内部(类内部)依然可以直接使用

    权限

    学习了封装后就可以控制属性的权限

    在python中只有两种权限

    1.公开的,默认的都是公开的

    2.私有的,只能当前类自己使用

    外界访问私有内容

    属性被封装后,外界需要使用时通过调用接口访问

    通过定义方法类完成对私有(封装)属性的修改和访问

    '''
    一个下载器的类,需要提供一个缓存大小的属性
    缓存大小不能超过内存限制
    '''
    class Download:
        def __init__(self, filename, url, buffer_memory):
            self.filename = filename
            self.url = url
            # 封装 缓存
            self.__buffer_memory = buffer_memory
        # 外界调用下载功能
        def start_download(self):
            # 判断缓存是否小于系统内存提供的缓存大小
            if self.__buffer_memory <= 1024*1024:
                print('开始下载...')
                print('当前缓存大小:%s'%self.__buffer_memory)
            else:
                print('超过内存缓存,内存爆炸...')
    ​
        # 提供给外界修改封装缓存接口
        def set_buffer_memory(self, size):
            if type(size) != int:
                print('请输入数字')
            else:
                self.__buffer_memory = size
                print('缓冲区修改成功')
    ​
        # 提供给外界访问缓存接口
        def check_buffer_memory(self):
            return self.__buffer_memory
    ​
    d = Download('黑猫警长','www.heihei.com',1024*1030)
    ​
    # 修改 缓存
    d.set_buffer_memory(1024*256)
    ​
    # 查看 缓存
    d.check_buffer_memory()
    ​
    d.start_download()
    ​
    # 这样我们可以在外界修改这个关键数据时,做一些限制

    property装饰器

    通过提供的方法(接口)修改或访问属性,本身没有问题,但是给对象的使用者带来了麻烦,使用时必须知道哪些是普通属性,哪些是私有属性,需要使用不同的使用方式来调用他们

    property装饰器就是为了使得调用方式一致,使访问方式和普通访问一样

    三个有关的装饰器

    1.@property     该装饰器用在属性的方法上
      def 属性名(self):
            return self.__属性名
    2.@属性名.setter   该装饰器用在修改属性的方法上
      def 属性名(self,新属性值):
            '''一些条件'''
            self.__属性名 = 新属性值
    3.@属性名.deleter   该装饰器用在删除属性的方法上
      def 属性名(self):
            del self.__属性名
    ​
    ps: setter 和 deleter 在有了 property 之后才能使用
    注意(看下面题):
        key是被 property 装饰的方法(函数)的名称,也就是属性的名称
        property 内部会创建一个对象key
        所以在使用 setter 和 deleter 时,必须保证使用对象的名称调用方法
        即: key.setter  /  key.deleter

    例:

    class A:
        def __init__(self, name, key):
            self.name = name
            self.__key = key
    ​
        @property
        def key(self):
            return self.__key
    ​
        @key.setter
        def key(self,new_key):
            # 可以加入一些判断
            if type(new_key) == int:
                self.__key = new_key
            else:
                print('需要整型')
    ​
        @key.deleter
        def key(self):
            # print('该属性不允许删除')
            del self.__key
            print('key已删除')
            
    a = A('xx',110)
    ​
    print(a.key)  # >>> 110
    ​
    a.key = 220
    print(a.key)  # >>> 220
    del a.key  # >>> key已删除

    python实现封装的原理

    就是在加载类的时候,把__替换成了_类名__

    class A:
        def __init__(self, name, pwd):
            self.name = name
            self.__pwd = pwd
    a = A('xx', 110)
    print(a.__dict__)  # >>> {'name': 'xx', '_A__pwd': 110}
    print(a._A__pwd)  # >>> 110

    property 可以用来实现计算属性

    计算属性指的是:属性的值,不能直接获得,必须通过计算才能获得

    如:正方形面积

    class Square:
        def __init__(self, length):
            self.length = length
            # self.area = length * length
        @property
        def area(self):
            return self.length * self.length
    ​
    s = Square(10)
    print(s.area)
    ​
    s.length = 20
    print(s.area)

    接口

    接口是一组功能的集合,但是接口中仅包含功能的名字,不包含具体的实现代码

    接口本质就是一套协议标准,遵循这个标准的对象就能被调用

    接口的目的就是为了提高扩展性

    例如:电脑提前指定制定一套USB接口协议,只要你遵循该协议,你的设备就可以被电脑使用,不需要关系到底是鼠标还是键盘

    class USB:
        def open(self):
            passdef close(self):
            passdef read(self):
            passdef write(self):
            passclass Mouse:
        def open(self):
            print("鼠标开机.....")
    ​
        def close(self):
            print("鼠标关机了...")
    ​
        def read(self):
            print("获取了光标位置....")
    ​
        def write(self):
            print("鼠标不支持写入....")
    ​
    def pc(usb_device):
        usb_device.open()
        usb_device.read()
        usb_device.write()
        usb_device.close()
    ​
    ​
    m = Mouse()
    # 将鼠标传给电脑
    pc(m)
    ​
    class KeyBoard(USB):
        def open(self):
            print("键盘开机.....")
    ​
        def close(self):
            print("键盘关机了...")
    ​
        def read(self):
            print("获取了按键字符....")
    ​
        def write(self):
            print("可以写入灯光颜色....")
    ​
    # 来了一个键盘对象
    k = KeyBoard()
    pc(k)

    在上述案例中,PC的代码一旦完成,后期无论什么样的设备,只要遵循USB接口协议,都能够被PC锁调用

    接口主要是方便了对象的使用者,降低使用者的学习难度,只要学习一套使用方法,就可以以不变应万变

    如果子类没有按照你的协议来设计,也没有办法限制他,将导致代码无法运行

    抽象类

    指的是包含抽象方法(没有函数体的方法)的类

    作用:可以限制子类必须类中定义方法

    最后:python一般不会限制你必须怎么写,作为一个优秀的程序员,就应该自觉遵守相关协议

    所以有了鸭子类型这么一说:

    如果这个对象长得像鸭子,走路像鸭子,那就他是鸭子

    你只要保证你的类按照相关的协议类编写,也可以达到提高扩展性的目的

  • 相关阅读:
    PTA——List Leaves
    pta——电话聊天狂人(c二叉树实现)
    Anti-SG游戏 与 SJ定理笔记(反Nim博弈)
    Unicode代码点与代码单元
    奇偶校验位
    IPv6与IPv4的位数
    0- win10配置java环境变量问题
    小计划
    路径问题
    getResource(path)的注意事项
  • 原文地址:https://www.cnblogs.com/waller/p/11251675.html
Copyright © 2011-2022 走看看