第三十二篇 面向对象三大特性之封装

什么是封装?

先抛开面向对象,单单去想什么是装,装就是找一个麻袋,把你喜欢的,不喜欢的,小猫,小狗,小鸡等等都装进麻袋里,这就是装。---对应到面向对象里,这个麻袋就是 类 或者 对象,类 或者 对象里(装的过程)定义的数据属性和函数属性就好比麻袋里的小猫,小狗。对类来说有自己的属性字典,对实例(对象)来说也有自己的属性字典,而这些方法,属性都存在了(装到了)各自的属性字典里去了。

而封,就是把麻袋口系上。---对应到面向对象里,封的概念代表隐藏。

封装合起来理解:就是把内容封起来,外部人看到的只有类名(麻袋),里面具体的方法,属性(小猫小狗)他是看不到的,就实现了隐藏的目的。

封装的本质,是要明确的区分内外 。

class People:
    def __init__(self, idnumber, name, age, salary):
        self.idnumber = idnumber
        self.name = name
        self.age = age
        self.salary = salary

    def get_id(self):
        print("你现在找到的是[%s]的身份证号:%s" %(self.name, self.idnumber))


if __name__ == '__main__':
    print(People.__dict__)
    p1 = People('34114134134314134134','小黄','24', '30000')
    p1.get_id()
示例1:People类

封装的第一层意义:

有上面一个People类,存在a.py文件里,此时在b.py文件里,去导入(import a),然后实例化,调用,等操作,这也是一种封装。实现了隐藏

from a import People

p2 = People('34114134432140980893','小黑','22', '10000')
p2.get_id()
封装的第一层意思:导入到另一文件使用

然后,封装远远不止这一层意思这么简单。

封装的第二层的封装:类中定义私有的,只在类内部使用,外部无法访问

和几个特性:

Python当中的定义的语言约定,这个约定并不是真正的限制,而是定义者和调用者达成的一种默契。

约定一: 单下划线开头:任何以单下划线开头的名字都应该是内部的,私有的。

属性名以单下划线开头,就是把数据隐藏在内部,不让外部看到。

这么做的目的,就是在调用者调的时候,只有看到是单下划线开头的,调用者就应该知道,这是内部属性,你需要知趣的不要再去调用了

class People:
    # 单下划线开头的属性
    _star = 'from earth'
    def __init__(self, idnumber, name, age, salary):
        self.idnumber = idnumber
        self.name = name
        self.age = age
        self.salary = salary

    def get_id(self):
        print("你现在找到的是[%s]的身份证号:%s" %(self.name, self.idnumber))


if __name__ == '__main__':
    p1 = People('34114134134314134134','小黄','24', '30000')
     # 调用单下划线的属性,实际上是可以调用的到的。然而,根据Python语言的约定,作为使用者,你就不应该去调用了。
    print(p1._star)   # from earth

上面的示例,让一脸茫然的我,还需要另一个解释,都说了是私有的,怎么还能被外部访问。记住这个解释:

这只是一种约定,Python并不会真正的阻止你访问私有属性,模块也遵循这种约定,如果模块名以单下划线开头,那么 from moudle import时是不能被导入的。

但是你from module import _private_module 依然可以导入的哦。

其实很多时候,你去调用一个模块的功能的时候回遇到单下划线开头的(socket._socket.sys._home, sys._home, sys._clear_type_cache)这些都是私有的,原则上是只供内部调用的,作为外部的你,一意孤行也是可以用的,只不过会遭到同行的鄙视。

约定二: 双下划线开头的属性。

class People:
    # 双下划线属性
    # 只要是__开头的属性,Python都会自动做一个重命名的操作,命名为:_类名__属性名
    __star = 'from earth double line'
    def __init__(self, idnumber, name, age, salary):
        self.idnumber = idnumber
        self.name = name
        self.age = age
        self.salary = salary

    def get_id(self):
        print("你现在找到的是[%s]的身份证号:%s" %(self.name, self.idnumber))


if __name__ == '__main__':
    print(People.__dict__)
    #结果
    '''
    {'__module__': '__main__', '_People__star': 'from earth double line', '__init__': <function People.__init__ at 0x105071730>, 
    'get_id': <function People.get_id at 0x1050717b8>, '__dict__': <attribute '__dict__' of 'People' objects>, 
    '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
    '''
    p1 = People('34114134134314134134','小黄','24', '30000')
    # 直接调用双下划线的属性,这个角度是调用不到了,看着是是实现了隐藏的目的。
    # print(p1.__star)   
    # AttributeError: 'People' object has no attribute '__star'
    # 换个方法调用,却能够调用的到
    print(p1._People__star)  # from earth double line

    # 这是为什么?
    '''
    原来,从类的字典属性里可以看到,Python对以双下划线开头的属性,都进行的重命名,命名规则是:_类名__属性名。
    所以,用重命名的属性名,当然就可以调用的到了
    '''

 第三个层面的封装,才是真正意义上的封装。明确区分内外,内部的去实现逻辑,外部的无法知晓,并且为封装到内部的逻辑提供一个访问接口给外部使用(这才是真正的封装,具体实现,会在面向对象进阶中讲,听着好高级的样子哦)

总结:

上面提到的两种不同的编码约定(单下划线和双下划线)来命名私有属性,那么问题来了:到底哪种方式好呢?

大多数情况下,你应该让你的非公共名称以单下划线开头,但是,如果你清楚你的代码会涉及到子类,并且有些内部属性应该在子类中隐藏起来,那么菜考虑使用双下划线方案。但是无论哪种方案,其实Python都没有从根本上限制你的访问。

说了半天,好像在说废话,得出的结论是:不可能完成真正的封装。没错,这不是你的错,也不是我的错,哈哈。是Python的错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值