【目录】@2020.4.8
一、引入
二、隐藏属性
1、如何隐藏属性
2、需要注意的几点问题
三、开放接口
1、隐藏数据接口
2、隐藏函数接口
四、装饰器property
面向对象编程有三大特性:封装、继承、多态,其中最重要的一个特性就是封装。
封装指的就是把数据与功能都整合到一起,之前所说的”整合“二字其实就是封装的通俗说法。
除此之外,针对封装到对象或者类中的属性,我们还可以严格控制对它们的访问,分两步实现:隐藏与开放接口
二、隐藏属性
1、为何要隐藏属性
-
隐藏数据属性,将数据隐藏起来就限制了类外部对数据的直接操作。
-
隐藏函数属性,目的是隔离程序的复杂度 。
2、如何隐藏属性?
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(obbj.__x) # 报错AttributeError:对象obj没有属性__x
3、需要注意的几点问题
(1)在类外部无法直接访问双下滑线开头的属性,但知道了类名和属性名就可以拼出名字: _类名__属性,然后就可以访问了,如foo._a__n所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。
class Foo: __x = 1 # _Foo__x def __f1(self): # _Foo__f1 print('from test') print(Foo.__dict__) # 查看类Foo的属性 print(Foo._Foo__x) # 访问隐藏的数据属性 __x print(Foo._Foo__f1) #访问隐藏的函数属性 __f1
(2) 这种隐藏对外不对内,即在类内部是可以直接访问双下滑线开头的属性的,比如self.__f1(),
因为在类定义阶段,类内部双下滑线开头的属性统一发生了变形。
class Foo: __x = 1 # _Foo__x = 1 def __f1(self): # _Foo__f1 print('from test') def f2(self): print(self.__x) # print(self._Foo__x) print(self.__f1) # print(self._Foo__f1) ,得到 _Foo__f1 的内存地址 print(self.__f1()) # print(self._Foo__f1()),打印函数 _Foo__f1的返回结果,先是打印输出 from test,再打印返回值,若未赋值,默认为None # print(Foo.__x) # AttributeError: type object 'Foo' has no attribute '__x' # print(Foo.__f1) # AttributeError: type object 'Foo' has no attribute '__f1' obj=Foo() obj.f2() # 输出结果: 1 <bound method Foo.__f1 of <__main__.Foo object at 0x000001B109AF9760>> from test None
#为何返回一个 None 值?
print(self.__f1()) # print(self._Foo__f1()),打印函数 _Foo__f1的返回结果,先是打印输出 from test,再打印返回值,若未赋值,默认为None
#为何返回一个 None 值?
1 class Foo: 2 __x = 1 # _Foo__x = 1 3 4 def __f1(self): # _Foo__f1 5 print('from test') 6 return 2 # 若没有设返回值,则默认返回 None 7 # return 'hello world' #也可返回字符串,可以返回任意格式正确的值 8 # return {1,2,3,4} 9 10 11 def f2(self): 12 print(self.__x) # print(self._Foo__x) 13 print(self.__f1) # print(self._Foo__f1) 14 print(self.__f1()) 15 16 # print(Foo.__x) # AttributeError: type object 'Foo' has no attribute '__x' 17 # print(Foo.__f1) # AttributeError: type object 'Foo' has no attribute '__f1' 18 obj=Foo() 19 obj.f2() 20 21 22 # 输出结果: 23 # 1 24 # <bound method Foo.__f1 of <__main__.Foo object at 0x000001801DAB9760>> 25 # from test 26 # 2 27 28 29 # ------将 f1改为正常的函数,不隐藏,直接执行 30 31 class Foo: 32 __x = 1 # _Foo__x = 1 33 34 def f1(self): # _Foo__f1 35 print('from test') 36 37 obj=Foo() 38 obj.f1() # 直接执行 f1() 39 40 # 输出结果: 41 from test 42 43 44 # -------不管f1隐藏与否, print(self.f1()) # print(self._Foo__f1()) ,都是在打印 f1方法的返回结果,一定要有个返回值,即return 返回值 45 46 class Foo: 47 __x = 1 # _Foo__x = 1 48 49 def f1(self): # _Foo__f1 50 print('from test') 51 return 1 # 若没有设返回值,则默认返回 None 52 53 def f2(self): 54 print(self.__x) # print(self._Foo__x) 55 print(self.f1) # print(self._Foo__f1) 56 print(self.f1()) # print(self._Foo__f1()) 打印 f1方法的返回结果,先是执行 print('from test'),再打印返回值,若没有设返回值,则默认返回 None 57 58 obj=Foo() 59 obj.f2() 60 61 # 输出结果: 62 1 63 <bound method Foo.f1 of <__main__.Foo object at 0x000001CA79079760>> 64 from test 65 1