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