面对对象的。 封装 property
封装的定义
封装是面向对象三大特性最核心的一个特性
封装就是将一段数据与功能打包并且封口,通过封装能控制接口
封装<========>整合
接口隐藏的方法
在类中的属性名前加__前缀,就会实现一个对外隐藏属性效果
注:隐藏本质是变形
加__前缀后可以使属性对外隐藏,但是其实本质上是
class Foo: __x = 1 # _Foo__x 在类定义阶段前检测语法时将双下划线开头的属性__x转换成_Foo__x的形式(_类名__属性名) def __f1(self): # _Foo__f1 print('from test') print(Foo.__dict__) print(Foo._Foo__x) print(Foo._Foo__f1) 导致在类外部无法直接访问双下滑线开头的属性__x,但知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如Foo._A__N, 所以说这种操作并没有严格意义上地限制外部访问,仅仅只是一种语法意义上的变形。
隐藏只对外
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) print(Foo.__x) print(Foo.__f1) obj=Foo() obj.f2()
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.__y=3 print(Foo.__dict__) print(Foo.__y) class Foo: __x = 1 # _Foo__x = 1 def __init__(self,name,age): self.__name=name self.__age=age obj=Foo('egon',18) print(obj.__dict__) print(obj.name,obj.age)
变形操作只会在检查类体语法的时候(定义前)发生一次,在此之后定义的__开头的属性都不会变形
隐藏的作用
定义出来还隐藏不是为了定义不了的,最后还是需要用的的。
-
控制接口的输入输出
# 设计者: class People: def __init__(self, name): self.__name = name def get_name(self): # 通过该接口就可以间接地访问到名字属性 print(self.__name) def set_name(self,val): if type(val) is not str: print('必须传字符串类型') return self.__name=val # 使用者: obj = People('egon') # print(obj.name) # 无法直接用名字属性 # obj.name = 'EGON' # 无法直接更改隐藏的属性 obj.set_name("哈哈") obj.get_name() 隐藏数据属性(将数据隐藏起来)就限制了类外部对数据的直接操作,然后类内应该提供相应的接口来允许类外部间接地操作数据,接口之上可以附加额外的逻辑来对数据的操作进行严格地控制
隔离复杂度:
- 隐藏数据属性(将数据隐藏起来)可以明显区分显式的属性与隐式的属性
- 以此来区分用户可用的属性 与 用户不可用的属性
- 只为用户显示可用属性,降低用户界面的复杂度
property
-
装饰器是在不修改被装饰对象源代码以及调用方式的前提下为被装饰对象添加新功能的可调用对象
property是一个装饰器,是用来绑定给对象的方法伪造成一个数据属性、 # 案例1 class People: def __init__(self, name, weight, height): self.name = name self.weight = weight self.height = height # 定义函数的原因1: # 1、从bmi的公式上看,bmi应该是触发功能计算得到的 # 2、bmi是随着身高、体重的变化而动态变化的,不是一个固定的值 # 说白了,每次都是需要临时计算得到的 # 但是bmi听起来更像是一个数据属性,而非功能 @property def bmi(self): return self.weight / (self.height ** 2) obj1 = People('umi', 62.5, 1.8) # print(obj1.bmi()) print(obj1.bmi) obj1.height=1.86 # print(obj1.bmi()) print(obj1.bmi) # 案例2 class People: def __init__(self, name): self.__name = name def get_name(self): return self.__name def set_name(self, val): if type(val) is not str: print('必须传入str类型') return self.__name = val def del_name(self): print('不让删除') # del self.__name name=property(get_name, set_name, del_name) obj1=People('egon') # print(obj1.get_name()) # obj1.set_name('EGON') # print(obj1.get_name()) # obj1.del_name() # 人正常的思维逻辑 print(obj1.name) obj1.name=18 del obj1.name # 案例3(推荐) class People: def __init__(self, name): self.__name = name @property def name(self): # obj1.name return self.__name @name.setter def name(self, val): # obj1.name='EGON' if type(val) is not str: print('必须传入str类型') return self.__name = val @name.deleter def name(self): # del obj1.name print('不让删除') # del self.__name obj1=People('egon') # 人正常的思维逻辑 print(obj1.name) obj1.name= 'EGON' print(obj1.name) del obj1.name