02-封装
Posted zhuyouai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了02-封装相关的知识,希望对你有一定的参考价值。
一、封装的基本概念
面向对象编程有三个特性:封装、继承、多态,其中封装特性极为重要。封装指的是把数据与功能整合到一起。当然针对封装到对象或者类中的属性,我们还可以严格控制对它们的访问,分两步实现:隐藏和开放接口
二、隐藏属性
Python
的机制Class
机制采用双下划线开头的方式将属性隐藏起来(设置成私有的),但其实这仅仅只是一种变形操作,类中所有双下划线开头的属性都会在类定义阶段、检测语法时自动变成_类名__属性名
的形式
class Foo:
__N = 0 # 变形为_Foo__N
def __init__(self): # 定义函数时,会检测函数语法,所以__开头的属性也会变形
self.__x = 10 # 变形为self._Foo__x
def __f1(self): # 变形为_Foo__f1
print("__f1 run")
def f2(self): # 定义函数时,会检测函数语法,所以__开头的属性也会变形
self.__f1() # 变形为self._Foo__f1()
print(Foo.__N) # 报错AttributeError:类Foo没有属性__N
obj = Foo()
print(obj.__x) # 报错AttributeError:对象obj没有属性__x
这种变形需要主要的问题是:
- 在类外部无法直接访问双下划线开头的属性,但知道了类名和属性名就可以拼出名字:
_类名__属性
,然后就可以访问了,如Foo._A__N
,所以说这种操作并没有严格意义上地限制外部访问,仅仅只是语法意义上的变形
>>> Foo.__dict__
mappingproxy({..., ‘_Foo__N‘: 0, ...})
>>> obj.__dict__
{‘_Foo__x‘: 10}
>>> Foo._Foo__N
0
>>> obj._Foo__x
10
>>> obj._Foo__N
0
- 在类内部时可以直接访问双下划线开头的属性的,比如
self.__f1()
,因为在类定义阶段内部双下划线的属性统一发生了变形
>>> obj.f2()
__f1 run
- 变形操作只是类定义阶段发生一次,在类定义之后的赋值操作,不会变形
>>> Foo.__M=100
>>> Foo.__dict__
mappingproxy({..., ‘__M‘: 100,...})
>>> Foo.__M
100
>>> obj.__y=20
>>> obj.__dict__
{‘__y‘: 20, ‘_Foo__x‘: 10}
>>> obj.__y
20
三、开放接口
定义属性就是为了使用,所以隐藏并不是目的
1.隐藏数据属性
将数据隐藏起来就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制
class Teacher:
def __oct__(self,name,age): # 将名字和年纪都隐藏起来
self.__name = name
self.__age = age
def tell_info(self): # 对外提供访问老师信息的接口
print("姓名:{},年龄:{}".format(self.__name,self.__age))
def set_info(self,name,age): # 对外提供设置老师信息的接口,并附加类型检查的逻辑
if not isinstance(name,str):
raise TypeError("姓名必须为字符串类型")
if not isinstance(age,int):
raise TypeError("年龄必须是整型")
self.__name = name
self.__age = age
teacher_obj = Teacher()
teacher_obj.set_info("LiLi","19")
"""
TypeError: 年龄必须是整型
"""
teacher_obj.set_info("lili",18)
teacher_obj.tell_info()
"""
姓名:lili,年龄:18
"""
2.隐藏函数属性
目的是为了隔离复杂度,例如ATM程序的取款功能,该功能有很多其他的功能组成,比如插卡、身份认证、输入金额、打印小票、取钱等,而对使用者来说,只需要开发取款这个功能接口即可,其余功能我们都可以隐藏起来
class ATM:
def __card(self): # 插卡
print("插卡")
def __auth(self): # 身份认证
print("身份认证")
def __input(self): # 输入金额
print("输入取款金额")
def __print_bill(self): # 打印小票
print("打印账单")
def __take_money(self): # 取钱
print("取款")
def witudraw(self): # 取款功能
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money()
ATM_obj = ATM()
ATM_obj.witudraw()
总结隐藏属性与开放接口,本质就是为了明确地区分开内外,类内部可以修改封装地东西而不影响外部调用者的代码,使用者均无需改变代码。这就提供一个良好的合作基础,只要接口这个基础约定不变,则代码的修改不足为虑
以上是关于02-封装的主要内容,如果未能解决你的问题,请参考以下文章