数据的封装 – 保护隐私
方法的封装 – 隔离复杂度
封装其实分为两个层面,但无论哪种层面的封装,都要对外界提供好访问你内部隐藏内容的接口(接口可以理解为入口,有了这个入口,使用者无需且不能够直接访问到内部隐藏的细节,只能走接口,并且我们可以在接口的实现上附加更多的处理逻辑,从而严格控制使用者的访问)
第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装
注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口
第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。
封装
在python中用双下划线的方式实现隐藏属性(设置成私有的)
封装 隐藏接口
1 2 3 4 5 6
| class A: __x = 1 def __test(self): print('from A') print(A.__dict__)
|
结果:
{‘module‘: ‘main‘, ‘_A__x‘: 1, ‘_Atest’: <function A.test at 0x000000000231BB70>, ‘dict‘: , ‘weakref‘: , ‘doc‘: None}
从打印的字典中可以查看到__A被隐藏成了_A__X,前面加上的_类的名字
1 2 3 4 5 6 7 8 9 10 11 12
| class A: __x = 1 def __test(self): print('from A') a = A() A._A__test(123123)
|
__名字只有在类中定义的时候才会产生变形,当类和对象已经产生了,就不会有变形的效果,可以直接拿来用,相当于普通的变量
1 2 3 4 5 6 7
| class B: pass B.__x = 1 print(B.__dict__) print(B.__x)
|
结果:
{‘module‘: ‘main‘, ‘dict‘: , ‘weakref‘: , ‘doc‘: None, ‘__x’: 1}
1
从字典中可以看到, ‘__x’: 1 没有变形成_B__x
1 2 3 4 5 6 7
| class B: # 已经产生了类 pass b = B() # 已经实例化了 b.__x = 1 print(b.__x) print(b.__dict__)
|
结果:
1
{‘__x’: 1}
查找的顺序
1 2 3 4 5 6 7 8 9 10 11
| class A: def fa(self): print("from A") def test(self): self.fa() class B(A): def fa(self): print("from B ") b = B() b.test()
|
结果:
from B
实例化后b.txt先从B中寻找,B中没有,从父类A中寻找,A中的test下面的执行的是self.fa(),实际的self还是传递的b,就是b.fa(),所以执行的还是B中的fa,所以运行的结果是 from B
把B中的注释
1 2 3 4 5 6 7 8 9 10
| class A: def fa(self): print("from A") def test(self): self.fa() class B(A): pass b = B() b.test()
|
结果:
from A
实际的原理就是b.test==b.fa()
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class A: def __fa(self): print("from A") def test(self): self.__fa() class B(A): pass b = B() b.test()
|
结果:
from A
小练习
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class A: def __fa(self): print("from A") def test(self): self.__fa() class B(A): pass b = B() b.test()
|
原理
查找的顺序
1 2 3 4 5 6 7 8 9 10 11
| class A: def fa(self): print("from A") def test(self): self.fa() class B(A): def fa(self): print("from B ") b = B() b.test()
|
结果:
from B
实例化后b.txt先从B中寻找,B中没有,从父类A中寻找,A中的test下面的执行的是self.fa(),实际的self还是传递的b,就是b.fa(),所以执行的还是B中的fa,所以运行的结果是 from B
把B中的注释
1 2 3 4 5 6 7 8 9 10
| class A: def fa(self): print("from A") def test(self): self.fa() class B(A): pass b = B() b.test()
|
结果:
from A
实际的原理就是b.test==b.fa()
封装的接口函数
在类的内部可以用__名字访问到变形的属性
对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了
1 2 3 4 5 6 7 8 9 10 11 12 13
| class A: def __init__(self): self.__x=1 def tell(self): print(self.__x) a=A() print(a.__dict__) a.tell()
|
模拟len(),通过调用函数的接口实现
1 2 3 4 5 6 7 8 9 10
| >>> a = 'hello' >>> l =[1,2,3,4] >>> def func(obj): ... return obj.__len__() ... >>> func(a) 5 >>> func(l) 4 >>>
|