zoukankan      html  css  js  c++  java
  • 类的封装

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

    一、为什么要封装

    封装数据的主要原因是:保护隐私(作为男人的你,脸上就写着:我喜欢男人,你害怕么?)

    封装方法的主要原因是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了,比如你不必知道你自己的尿是怎么流出来的,你直接掏出自己的接口就能用尿这个功能)

    提示:在编程语言里,对外提供的接口(接口可理解为了一个入口),就是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。

    二、如何使用代码实现隐藏

    隐藏属性:通过 __变量名来隐藏

    隐藏方法:通过 __方法名来隐藏

    2.1 隐藏属性

    隐藏属性是为了安全

    class Person:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
        def get_name(self):
            # print(self.__name)
            return '[----%s-----]'%self.__name
        
    p=Person('xc',18)
    # print(p.age)	# 错误的使用方法
    # print(p.__name)	# 错误的使用方法
    print(p.get_name())
    

    实际上 __变量名 是通过变形隐藏了属性

    2.1.1 隐藏的属性访问不到?

    实际上由方法可以访问到。但是大家不要去这样用。

    之前说了是通过 变形 隐藏了属性

    # 通过__dict查看对象私有属性
    print(p.__dict__)
    
    # 通过变形后的属性,一样可以拿到变量内容
    print(p._Person__age) # 不要这样用
    

    [----xc-----]
    {'_Person__name': 'xc', '_Person__age': 18}

    2.2 隐藏方法

    隐藏方法,隔离复杂度

    class Person:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
        def __speak(self):
            print('6666')
            
    p=Person('xc',18)
    p.__speak()	# 错误的使用方法
    
    # 查看类中的私有属性
    print(Person.__dict__)
    

    {'module': 'main', 'init': <function Person.init at 0x000001E3C2CA29D8>, '_Person__speak': <function Person.__speak at 0x000001E3C2CA2A60>, 'dict': <attribute 'dict' of 'Person' objects>, 'weakref': <attribute 'weakref' of 'Person' objects>, 'doc': None}
    6666

    2.3 什么情况的属性变形

    只要在类内部,以 __变量名 命名的变量,都会被隐藏,会发生变形。

    但,如果在外部放入__变量名 属性是不隐藏的

    class Person:
        def __init__(self,name,age):
            self.__name=name
            self.__age=age
        def set_xx(self,xx):
            self.__xx=xx
    
    p=Person('xc',18)
    p._p_aa="aaa"	# 没有被隐藏
    
    p.set_xx('6688')	# 被隐藏
    print(p.__dict__)
    

    {'_Person__name': 'nick', '_Person__age': 18, '_p_aa': 'aaa', '_Person__xx': '6688'}

    三、property装饰器

    3.1 property装饰器有什么用

    它可以把方法包装成数据属性

    class Person:
        def __init__(self,name,height,weight):
            self.name=name
            self.height=height
            self.weight=weight
        @property	# 使用语法糖的方式 通过property装饰器进行装饰
        def bmi(self):
            return self.weight/(self.height**2)
        
    p=Person('xc',1.82,75)
    print(p.bmi)	# 使用查看对象属性的方式  查看方法的返回值
    # print(p.bmi())	# 错误的使用方法
    # p.bmi = 123   # 只能查看,不能进行修改
    

    22.6421929718633

    3.2 property之setter和deleter

    使用property装饰器将方法包装成数据属性后,是无法进行修改的

    • 只要通过property装饰器中的方法 .setter,这样就可以修改了
    class Person:
        def __init__(self,name,height,weight):
            self.__name=name
            self.__height=height
            self.__weight=weight
        @property
        def name(self):
            return '[我的名字是:%s]'%self.__name
    
        #用property装饰的方法名.setter,这样就可以修改了
        @name.setter
        def name(self,new_name):
            # if not isinstance(new_name,str):
            if type(new_name) is not str:
                raise Exception('改不了')
            if new_name.startswith('sb'):
                raise Exception('不能以sb开头')
            self.__name=new_name
            
    p=Person('xc',1.82,70)
    # 按照属性进行调用
    print(p.name)	# 调用property装饰器后的方法 name,变为一个属性
    # 按照属性进行调用,并修改
    p.name='pppp'	# 调用property.setter装饰器后的方法,可以进行修改
    
    # 改不了,直接抛异常
    # p.name=999
    # p.name='sb_xxx'
    
    • 只要通过property装饰器中的方法 .deleter,就可以删除了

    一般没有这个需求。

    class Person:
        def __init__(self, name, height, weight):
            self.__name = name
            self.__height = height
            self.__weight = weight
    
        @property
        def name(self):
            return '[我的名字是:%s]' % self.__name
    
        # 用property装饰的方法名.setter,这样就可以修改了
        @name.setter
        def name(self, new_name):
            # if not isinstance(new_name,str):
            if type(new_name) is not str:
                raise Exception('改不了')
            if new_name.startswith('sb'):
                raise Exception('不能以sb开头')
            self.__name = new_name
    
    
    p = Person('xc', 1.82, 70)
    # 按照属性进行调用
    print(p.name)  # 调用property装饰器后的方法 name,变为一个属性
    # 按照属性进行调用,并修改
    p.name = 'pppp'  # 调用property.setter装饰器后的方法,可以进行修改
    # 改不了,直接抛一异常
    # p.name=999
    # p.name='sb_xxx'
    
    # 删除name,会调用property.deleter装饰的方法
    del p.name
    
  • 相关阅读:
    研磨设计模式
    Java 集合类
    晚上提高项目效率,下午安卓又是过
    晚上提高项目效率,下午安卓又是过
    项目已经进行到医生管理,在完成文本框这个导入后就基本上剩下导出表格数据了
    晚上开始就要解决这个查询乱码的问题
    现在不能使用foxmail同步qq记事本功能,可能是对字数的大小有限制
    早上看到一张余票,可是没有等网页进入到结果页面,网络原因就票没了
    早上看到一张余票,可是没有等网页进入到结果页面,网络原因就票没了
    昨天晚上也弄不清楚是自己密码被盗了还是由于ip冲突
  • 原文地址:https://www.cnblogs.com/XuChengNotes/p/11425764.html
Copyright © 2011-2022 走看看