封装

封装

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

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

封装的目的

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一般不会限制你必须怎么写,作为一个优秀的程序员,就应该自觉遵守相关协议

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

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

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

posted @ 2019-07-26 17:19  waller  阅读(311)  评论(0编辑  收藏  举报