zoukankan      html  css  js  c++  java
  • 面向对象之封装之如何隐藏属性, 封装的底层原理

    1.什么是封装:?
    封:属性对外是隐藏的,但对内是开放的。
    装:申请一个名称空间,往里装入一系列名字/属性。(类和对象都是有一个名称空间,往里面装一系列的名字)


    2、为什么要封装
    封装数据属性的目的
    首先定义属性的目的就是为了给类外部的使用使用的,
    隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
    然后让类外部的使用通过接口来间接地操作隐藏的属性。
    精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作

    封装函数属性
    首先定义属性的目的就是为了给类外部的使用使用的,
    隐藏函数属性是为了不让外不直接使用,需要类内部开辟一个接口
    然后在接口内去调用隐藏的功能
    精髓在于:隔离了复杂度



    3、如何封装


    注意:
    如何隐藏?
    再属性前面加__开头

    重点:这种隐藏式对外不对内的,即再类的内部可以直接访问,而在类的外部则无法直接访问。原因是在类定义阶段,类体内代码
    统一发生了一次变形。

    下面是证明上面一行话的例子:
    一种情况:
    再类的里面隐藏数据属性,类再内部可以访问到这个隐藏的属性,类再类的外部就访问不到这个隐藏的属性了
    class People:
    __county='china' #再想隐藏的属性前面加__开头
    def __init__(self,name,age,sex):
    self.name=name
    self.age=age
    self.sex=sex
    def eat(self):
    print('eat...')
    print(People.__county) #再类的内部调用改变过的属性。通过类名调用属性。
    peo1=People('egon',18,'male')
    # People.eat(111) #调用函数后,print(People.__county)能访问到,说明对内能访问到
    print(People.__county) #再外部直接访问改变后的属性,会报错

    二种情况:
    # 再类的里面隐藏数据属性或者函数属性,对象再内部可以访问到隐藏的属性,对象再类的外部就访问不到隐藏的属性。
    # class People:
    # __county='china' #再想隐藏的属性前面加__开头
    # def __init__(self,name,age,sex):
    # self.__name=name #隐藏属性名
    # self.age=age
    # self.sex=sex
    # def eat(self):
    # print('eat...')
    # print(self.__name) #对象在类内部调用隐藏的属性
    # peo1=People('egon',18,'male')
    # peo1.eat() #验证对象在类内部可以访问到隐藏的属性。
    # print(peo1.__name) #验证对象在类外部访问不到隐藏的属性。


    封装的底层原理

    2.这种语法上的变形只在定义阶段发生一次,因为类体代码仅仅只在类定义阶段检查一次
    例如:
    # 只要是__开头的属性,它在往名称空间里面丢的时候,都做了一个变形。成了_类名__属性名
    class People:
    __county='china' #_People__county
    __n=100
    def __init__(self,name,age,sex):
    self.__name=name #
    self.age=age
    self.sex=sex
    def eat(self):
    print('eat...')
    # print(People.__county)
    print(self.__county)
    s1=People('egon',18,'male')
    s1.eat()
    # print(People.__dict__) #查看People里面的隐藏属性都做了变形,成了_People__county
    print(People._People__county) #直接访问这个变了形的属性名,可以直接访问到
    People.__x=1    #再这里__x不会变形,因为这个变形只在类定义阶段发生一次,定义阶段变形后,其他再操作__开头都没用了
    print(People.__dict__)


    # 总结:这种隐藏仅仅是一种语法上的变形操作。

    为什么在内部可以访问到被隐藏的属性?
    因为类再定义阶段就会执行类体代码,执行之前会先检测语法,这个检测只在类定义阶段发生一次
    再内部能访问到,是因为内部的访问再当初检测语法的时候,都一块变形了。都变成了
    最真实的形式


    实例训练:
    class Foo:
    def __f1(self): #_Foo__f1
    print('Foo.f1')
    def f2(self):
    print('Foo.f2')
    self.__f1() #self._Foo__f1()
    class Bar(Foo):
    def __f1(self): #_Bar__f1
    print('Bar.f1')
    obj=Bar()
    obj.f2()

    结果是:

    Foo.f2
    Foo.f1

    总结:如果不想让子类的方法覆盖父类的,可以该方法名前加一个__开头。


    用隐藏属性这个方法,是如何用呢?


    封装数据属性的目的
    首先定义属性的目的就是为了给类外部的使用使用的,
    隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
    然后让类外部的使用通过接口来间接地操作隐藏的属性。
    精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作

    # 想严格控制属性的类型。要做两步:
    # 一步是:隐藏属性,外部看不到,想看设计者可以在内部开一个接口,
    # 直接用这个接口,再接口内附加一些控制的逻辑
    def set_info(self,name,age): #开一个接口,可以改里面的属性。
    if type(name) is not str:
    # print('用户名必须为str类型')
    # return
    raise TypeError('用户名必须为str类型')

    if type(age) is not int:
    # print('年龄必须为int类型')
    # return
    raise TypeError('年龄必须为int类型')
    self.__name=name
    self.__age=age

    peo1=People('egon',18)
    # peo1.name=123 #再原来没有隐藏属性的时候,类型可以随便用,没限制,123也没关系
    # peo1.age
    # peo1.tell_info()

    peo1.set_info('egon',19)
    # peo1.tell_info()


  • 相关阅读:
    Spring进阶—如何用Java代码实现邮件发送(一)
    如何在Apache中使用PHP处理PHP文件
    最“高大上”的Spring测试:Spring Test
    【编程直播】来约吗?
    【PaPaPa】实现缓存决策
    【PaPaPa】系统架构搭建浅析
    【PaPaPa】集成B/S主流技术的MVC5项目
    【轮子狂魔】手把手教你自造Redis Client
    【轮子狂魔】抛弃IIS,打造个性的Web Server
    【轮子狂魔】抛弃IIS,向天借个HttpListener
  • 原文地址:https://www.cnblogs.com/fxc-520520/p/9239754.html
Copyright © 2011-2022 走看看