• OOP >>> 封装


    封装:

      隐藏对象的属性和实现细节,仅对外提供公共访问属性

      原则

        1. 将不需要对外提供的内容都隐藏起来;

        2. 把属性都隐藏,提供公共方法对其访问(接口)

      好处

        1. 将变化隔离; 

        2. 便于使用;

        3. 提高复用性; 

        4. 提高安全性;

    封装原理:就是在加载类的时候,把_ _属性  替换成了  _类名_ _属性

    封装可以分为:对象的变量封装 >>> 私有变量           语法:在python中用 双下划线开头 的方式将属性隐藏起来(设置成私有的)

             对象的方法封装 >>> 私有方法           语法:在python中用 双下划线开头 的方式将属性隐藏起来(设置成私有的)

    私有变量:

    class Person:
        def __init__(self, id_number, name, age):
            self.__id_number = id_number  # 将身份证号码封装为私有属性/变量
            self.name = name
            self.age = age
    
        def show_id(self):
            print(self.__id_number)
    
    p = Person("1111111111111", "jack", 29)
    
    p.__id_number = "222"  # 这里只是增加了一个p的属性,不是重新赋值
    print(p.__id_number)  # 222  访问的是p的__id_number属性
    
    p.show_id()  # 1111111111111  # 原始的id_number并没有被改
    
    print(p._Person__id_number)  # 1111111111111  此方式可以访问到原始值
    
    # 变形的过程只在类的内部生效,在定义后的赋值操作,不会变形
    # 类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式 # p._Person__id_number是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
    # 在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的

    私有方法:

    
    
    class PC:
    def __init__(self,price,kind,color):
    self.price = price
    self.kind = kind
    self.color = color

    def open(self): # 定义为共有方法,可直接调用
    print("接通电源")
    self.__check_device()
    print("载入内核")
    print("初始化内核")
    self.__start_services()
    print("启动GUI")
    self.__login()


    def __check_device(self): # 定义为私有方法
    print("硬件检测1")
    print("硬件检测2")
    print("硬件检测3")
    print("硬件检测4")

    def __start_services(self): # 定义为私有方法
    print("启动服务1")
    print("启动服务2")
    print("启动服务3")
    print("启动服务4")

    def __login(self): # 定义为私有方法
    print("login....")
    print("login....")
    print("login....")

    pc1 = PC(20000,"香蕉","黄色")
    pc1.open() # 执行函数open(),同时执行函数内部的其他隐藏函数
    pc1.login() # AttributeError: 'PC' object has no attribute 'login' 没有此函数
    pc1._PC__login() # 直接访问到__login函数

    # 定义为私有方法后,只能从类的内部访问到,外界不能直接访问

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

    如何访问被封装的属性????

      前面其实已经可以看出,我们可以通过类内部的函数方法来访问,甚至可以对被封装后的属性进行修改。如下:

    """
    这是一个下载器类,需要提供一个缓存大小这样的属性
    缓存大小不能超过内存限制
    
    """
    class Downloader:
        def __init__(self,filename,url,buffer_size):
            self.filename = filename
            self.url = url
            self.__buffer_size= buffer_size  # 设置为私有属性
    
        def start_download(self):
            if self.__buffer_size <= 1024*1024:
                print("开始下载....")
                print("当前缓冲器大小",self.__buffer_size)
            else:
                print("内存炸了! ")
    
    
        def set_buffer_size(self,size):
            #可以在方法中添加额外的逻辑-------------->设置为私有属性,就是不想让被直接访问到,所以在通过类内部函数访问时,可以增加一些限制条件
            if not type(size) == int:  # 只有条件满足,才能执行函数体代码
                print("大哥 缓冲区大小必须是整型")
            else:
                print("缓冲区大小修改成功!")
                self.__buffer_size = size  # 执行的结果,成功修改隐藏的私有属性
    
        def get_buffer_size(self):  # 通过类内部函数访问隐藏的私有属性
            return self.__buffer_size
    
    d = Downloader("葫芦娃","http://www.baicu.com",1024*1024)
    
    d.start_download()  # 开始下载....  当前缓冲器大小 1048576
    
    
    # 通过函数取修改内部封装的属性d.set_buffer_size(1024*512)  # 缓冲区大小修改成功!# 通过函数访问内部封装的属性print(d.get_buffer_size())  # 524288print(d.filename)  # 葫芦娃

    Property装饰器:

      虽然我们可以通过类内部函数来访问隐藏的私有属性,但是对于不知状况的用户来讲就有点麻烦了,使用必须知道哪些是普通属性,哪些是私有属性,需要使用不同的方式来调用他们  。所以我们需要对这些函数进行一些装饰,让其可以直接像公开属性一样直接被访问,但是还是对其修改上做了一定的限制,限制其职能被修改为特定的形式。

      property装饰就是为了使得调用方式一致(使用property装饰器可以将一个方法伪装成普通属性,保证属性之间调用方法一致)

      @property                  该装饰器用在获取属性的方法上

      @隐藏属性名.setter       该装饰器用在修改属性的方法上

      @隐藏属性名.deleter     该装饰器用在删除属性的方法上

    class A:
        def __init__(self,name,key):
            self.name = name
            self.__key = key  # 定义为私有属性
    
        @property  # 装饰器  可以实现get,set,delete三种方法  #只有在属性key定义property后才能定义key.setter,key.deleter
        def key(self):
            return self.__key  # get私有属性值
    
        @key.setter  # 可以对私有属性的值进行修改
        def key(self,new_key):
            if new_key <= 100:  # 在设定值之前进行条件判断
                self.__key = new_key
            else:
                print("key 必须小于等于100")
    
        @key.deleter  # 可以对私有属性进行删除操作,但是返回的结果需要看内部的函数体代码 
        def key(self):
            print("不允许删除该属性")
            del self.__key
    
    a = A("jack",123)
    print(a.key)  # 123  可以间接访问到,但是用户并不知道中间执行了函数,还以为是直接跟访问name一样直接访问的
    
    a.key = 321  # key 必须小于等于100 >>> 修改过程
    
    print(a.key)  # 123    由于修改时候条件不成立,所以返回的还是原值。若是公开属性,那么这一步骤就直接执行,key直接被修改
    
    del a.key  # 不允许删除该属性  私有属性不会像公开属性一样直接就可以被删除

       此外,Property 还具有计算属性(属性的值不能直接获得,必须通过计算才能获取 ),可应用于下面的场景:

    # 练习: 定义一个类叫做person
    # 包含三个属性 身高 体重   BMI
    # BMI的值需要通过计算得来 公式   体重 / 身高的平方
    
    
    class Square:
    
        def __init__(self,width):
            self.width = width
    
        @property  # 执行一段功能(函数)然后返回值
        def area(self):
            return self.width * self.width
    
    s = Square(10)
    
    print(s.area)  # 100  可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
    
    s.width = 20
    
    print(s.area)  # 400
    
    s.width = 2
    print(s.area)  # 4

     ################################

    补充:一个静态属性property本质就是实现了get,set,delete三种方法:如下:

    class Foo:
        @property
        def AAA(self):
            print('get的时候运行我啊')
    
        @AAA.setter
        def AAA(self,value):
            print('set的时候运行我啊')
    
        @AAA.deleter
        def AAA(self):
            print('delete的时候运行我啊')

    # 上面的三个函数就相当于类内部的一个变量,变量AAA = 一个值
    f1=Foo() # 实例化过程 f1.AAA # 查看公开属性 f1.AAA='aaa' # 对属性进行修改操作 del f1.AAA # 对属性进行删除操作

     ################################

     接口:

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

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

      目的:提高扩展性

      接口是一套协议规范,明确子类们应该具备哪些功能

      抽象类是用于强制要求子类必须按照协议中规定的来实现 

      如何强制???如下:

    import abc
    
    
    class USB(metaclass=abc.ABCMeta):
    
        @abc.abstractmethod  # 用来限制子类,假如子类没有此方法,具不能正常使用
        def run(self):
            print('你好啊')
    
        @abc.abstractmethod
        def close(self):
            pass
    
        @abc.abstractmethod
        def read(self):
            pass
    
        @abc.abstractmethod
        def write(self):
            pass
    
    
    class Mouse(USB):
    
        def run(self):
            print('1')
    
        def close(self):
            print('2')
    
        def read(self):
            print('3')
    
        def write(self):
            print('4')
    
    
    class KeyBoard(USB):
        
        pass
    
    k = KeyBoard()  # 由于KeyBoard这个USB的子类内部没有相应的功能代码,导致不能使用的情况
    k.close() # TypeError: Can't instantiate abstract class KeyBoard with abstract methods close, read, run, write
    m = Mouse() # Mouse类内部具有跟USB一样的功能,所以代码能正常使用 m.run() # 1

      

  • 相关阅读:
    C#学习笔记10
    C#学习笔记9
    C#学习笔记8
    C#学习笔记7
    C#学习笔记6
    C#学习笔记5
    C#学习笔记4
    distinct() 去重复
    row_number over ()排序函数
    当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。
  • 原文地址:https://www.cnblogs.com/pupy/p/11252604.html
Copyright © 2020-2023  润新知