面向对象——封装

谁借莪1个温暖的怀抱¢ 2021-09-19 13:14 580阅读 0赞

封装

层次一:类就是麻袋,这本身就是一种封装

  1. 从字面意义上去理解封装,装就是搬家的时候,把书、电脑、杯子什么的都往袋子里装,封就是把这个袋子封起来,封起来之后,从外面就什么都看不到了,就是所谓的‘隐藏’。在面向对象里面,这个袋子就是类或者对象,下面举个例子:

复制代码

  1. class People:
  2. star = 'earth'
  3. def __init__(self,id,name,age):
  4. self.id = id
  5. self.name = name
  6. self.age = age
  7. def get_id(self):
  8. print('我是私有方法,我的id是%s'%self.id)

复制代码

  1. 定义好这个类之后,其他人要调用你的类,就是这样的:
  2. from (文件名) import People
  3. p1 = People('2131415151','pengfy',18)
  4. p1.get_id()
  5. >>> 我是私有方法,我的id2131415151
  6. 我可以使用你这个类,但是并不知道你具体是怎么实现的,这就属于一种封装,但封装并不只是隐藏。

层次二:类中定义私有的,只有在类的内部才能使用,外部无法使用

  1. 首先,什么是内部,什么是外部?在类里面用就是内部,调用这个类再使用,就是外部喽。那怎么定义私有呢?说这个之前,就要说要Python的两个约定:

1.单下划线开头

  1. 类里面单下划线开头的属性,一般都是定义的私有,继续看上面的例子:

复制代码

  1. # -*- coding: utf-8 -*-
  2. class People:
  3. star = 'earth'
  4. _star = 'earth1'
  5. def __init__(self,id,name,age):
  6. self.id = id
  7. self.name = name
  8. self.age = age
  9. def get_id(self):
  10. print('我是私有方法,我的id是%s'%self.id)
  11. p1 = People('2131415151','pengfy',18)
  12. print(p1.star)
  13. print(p1._star)

复制代码

运行一下,结果是:

  1. >>>earth
  2. >>>earth1
  3. 说好的私有呢?怎么都能打印,但是,请记住,这只是一个约定,你非要调用,还是可以的,哈哈。

2.双下划线开头

复制代码

  1. # -*- coding: utf-8 -*-
  2. class People:
  3. star = 'earth'
  4. _star = 'earth1'
  5. __star = 'earth2'
  6. def __init__(self,id,name,age):
  7. self.id = id
  8. self.name = name
  9. self.age = age
  10. def get_id(self):
  11. print('我是私有方法,我的id是%s'%self.id)
  12. p1 = People('2131415151','pengfy',18)
  13. print(p1.star)
  14. print(p1._star)
  15. print(p1.__star)

复制代码

  1. 看一下运行结果:
  2. >>> earth
  3. >>> earth1
  4. AttributeError: 'People' object has no attribute '__star'
  5. 报错了,好像可以啊,双下划线外部不能访问嘛,你可以试试内部能不能访问,肯定是可以的,这就完了私有属性啦?有点早,不信你试试把p1.\_\_star替换成p1.\_People\_\_star,运行结果如下:

复制代码

  1. class People:
  2. star = 'earth'
  3. _star = 'earth1'
  4. __star = 'earth2'
  5. def __init__(self,id,name,age):
  6. self.id = id
  7. self.name = name
  8. self.age = age
  9. def get_id(self):
  10. print('我是私有方法,我的id是%s'%self.id)
  11. p1 = People('2131415151','pengfy',18)
  12. print(p1.star)
  13. print(p1._star)
  14. print(p1._People__star)
  15. >>>earth
  16. >>>earth1
  17. >>>earth2

复制代码

  1. 写成这样就出来啦?为什么要这么写?自己找答案!打开类的属性字典找找就好了:
  2. print(People.__dict__)
  3. >>>{'__module__': '__main__', 'star': 'earth', '_star': 'earth1', '_People__star': 'earth2', '__init__': <function People.__init__ at 0x00000206A3BF26A8>, 'get_id': <function People.get_id at 0x00000206A3BF2730>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
  4. 找到没有,Python中类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如\_\_star,会变形为\_People\_\_star,这种变形需要注意的是:

1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._C__D,*即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问。*

2.变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形,看下边例子就知道了

复制代码

  1. class People:
  2. star = 'earth'
  3. _star = 'earth1'
  4. __star = 'earth2'
  5. def __init__(self,id,name,age):
  6. self.id = id
  7. self.name = name
  8. self.age = age
  9. def get_id(self):
  10. print('我是私有方法,我的id是%s'%self.id)
  11. p1 = People('2131415151','pengfy',18)
  12. print(p1.__dict__)
  13. p1.__star = 'earth666'
  14. print(p1.__dict__)
  15. >>>{'id': '2131415151', 'name': 'pengfy', 'age': 18}
  16. >>>{'id': '2131415151', 'name': 'pengfy', 'age': 18, '__star': 'earth666'}

复制代码

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

复制代码

  1. #正常情况
  2. >>> class A:
  3. ... def fa(self):
  4. ... print('from A')
  5. ... def test(self):
  6. ... self.fa()
  7. ...
  8. >>> class B(A):
  9. ... def fa(self):
  10. ... print('from B')
  11. ...
  12. >>> b=B()
  13. >>> b.test()
  14. from B
  15. #把fa定义成私有的,即__fa
  16. >>> class A:
  17. ... def __fa(self): #在定义时就变形为_A__fa
  18. ... print('from A')
  19. ... def test(self):
  20. ... self.__fa() #只会与自己所在的类为准,即调用_A__fa
  21. ...
  22. >>> class B(A):
  23. ... def __fa(self):
  24. ... print('from B')
  25. ...
  26. >>> b=B()
  27. >>> b.test()
  28. from A

复制代码

层次三:明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个借口供外部使用(这才是真正意义的封装,不要为了封装而封装)

  1. 上面已经知道了,双下划线开头,外部无法直接访问,但是内部可以,这样的话,你可以定义一个函数直接return出去,就OK了:

复制代码

  1. class People:
  2. star = 'earth'
  3. _star = 'earth1'
  4. __star = 'earth2'
  5. def __init__(self,id,name,age):
  6. self.id = id
  7. self.name = name
  8. self.age = age
  9. def get_id(self):
  10. print('我是私有方法,我的id是%s'%self.id)
  11. def tell_star(self):
  12. return self.__star
  13. p1 = People('2131415151','pengfy',18)
  14. print(p1.tell_star())
  15. >>> earth2

复制代码

  1. 这样做外部要拿这个属性时,也可以拿到,tell\_star这个函数就是这个类的接口函数,当然上面的例子讲的都是数据属性,函数属性呢?肯定也是一样可以:

复制代码

  1. #取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
  2. #对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
  3. #隔离了复杂度,同时也提升了安全性
  4. class ATM:
  5. def __card(self):
  6. print('插卡')
  7. def __auth(self):
  8. print('用户认证')
  9. def __input(self):
  10. print('输入取款金额')
  11. def __print_bill(self):
  12. print('打印账单')
  13. def __take_money(self):
  14. print('取款')
  15. def withdraw(self):
  16. self.__card()
  17. self.__auth()
  18. self.__input()
  19. self.__print_bill()
  20. self.__take_money()
  21. a=ATM()
  22. a.withdraw()

复制代码

  1. 打印一下结果:
  2. 插卡
  3. 用户认证
  4. 输入取款金额
  5. 打印账单
  6. 取款
  7. 了解:

python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果模块名以单下划线开头,那么from module import \时不能被导入,但是你from module import _private_module依然是可以导入的*

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

python要想与其他编程语言一样,严格控制属性的访问权限,只能借助内置方法如__getattr__,这里就不做讲解

  1. 小结:
  2. 封装看起来简单,但不要去为了封装而封装,要提前识别哪些数据要使用,那些数据需要隐藏,不能滥用双下划线,否则的话,项目做到后期,你的类里面会出现很多接口函数,这也就是麻袋上面的洞,那么你的类看起来也是烂七八糟,后面会持续补充其他封装的内容,封装不只是这么简单。

如果你对编程感兴趣或者想往编程方向发展,可以关注微信公众号【筑梦编程】,大家一起交流讨论!小编也会每天定时更新既有趣又有用的编程知识!

发表评论

表情:
评论列表 (有 0 条评论,580人围观)

还没有评论,来说两句吧...

相关阅读

    相关 面向对象——封装

           在面向对象程序中,就是把对象的属性和操作结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。在java中主要体现为类对属性和方法的封装和方法对方法具体的实现细节

    相关 面向对象封装

    封装 该露的露,该藏的藏 我们程序设计要追求“高内聚,低耦合”。 高内聚就是类的内部数据操作细节自己完成,不允许外部干涉; 低耦合:仅暴露少量的方法给外部使用。

    相关 面向对象——封装

    封装的通俗介绍 我们日常使用的电脑主机,把cpu,内存,主板等等都封装到机箱里面去。假如没有机箱的话就会出现主机,主板全部都散落在一处,然后开机没有开机按钮,那么需要我们

    相关 面向对象封装

    封装 隐藏细节 - 抽离共有 封装: 对外隐藏类中一些属性与方法的实现细节 优点:外界不能直接访问,让内部的属性与方法具有安全保障 clas

    相关 面向对象——封装

    面向对象——封装 面向对象 面向过程:当需要实现一个功能的时候,每一个具体的步骤都要亲力亲为,详细处理每一个细节。 面向对象:当需要实现一个功能的时候,

    相关 面向对象封装

    一、什么是封装 什么是封装,就是将复杂的丑陋的,隐私的细节隐藏到内部,对外提供简单的使用接口,对外隐藏内部实现细节,并提供访问的接口 二、为什么需要封装 两个目的:1.为

    相关 python面向对象: 封装

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