封装
一、什么是封装
对外部隐藏内部的属性和细节方法,仅提供简单的访问接口。(注意:封装有隐藏的意思但不是单纯的隐藏)
二、封装的目的
限制外界对内部数据的访问,提高内部数据的安全性和隔离复杂度。
封装属性:提高数据的安全性。将数据属性隐藏起来,类外就无法直接操作属性,需要类内开辟一个接口来让外部使用。因此,可以在接口内控制任意的控制逻辑,从而严格控制使用者对数据的查看或者修改
封装方法:隔离复杂度。一个内部提供支持的方法,不因该让外界直接访问,就可以直接封装起来
三、如何封装
在类内定义的属性或方法方法前加 __ 开头,没有 __结尾
3.1 封装属性
# # 封装属性 class Teacher: def __init__(self,name,age,salary): self.name = name self.age = age self.__salary = salary # 访问被封装的属性,称之为访问器 def get_salary(self,pwd): # 可以在接口处添加额外的任何逻辑,来限制外部的访问 if pwd == "123": return self.__salary # 在类的内部,可以访问 raise Exception("密码错误") # 修改被封装的属性,称之为设置器 def set_salary(self,new_salary): self.__salary = new_salary t = Teacher("wangyong",25,10000) # print(t.__salary) # 报错 AttributeError: 'Teacher' object has no attribute '__salary' t.get_salary("123") # 10000 t.set_salary(15000) t.get_salary() # 15000 t.__hello = 20 print(t.__hello) # 20
3.2 封装方法
class ATM: def __user_auth(self): print("请输入账号密码") def __input_money(self): print("请输入取款金额") def __save_record(self): print("记录流水....") def withdraw(self): self.__user_auth() self.__input_money() self.__save_record() atm = ATM() atm.withdraw() atm.__user_auth() # 报错 AttributeError: 'ATM' object has no attribute '__user_auth' atm._ATM__user_auth() # 请输入账号密码
四、封装的原理
python是通过 变形的方式来实现的封装
如何变形:在名称带有双下划线开头的变量名字前添加_类名 如_Person__id_card
当然通过变形后的名字可以直接访问被隐藏的属性 但通过不应该这么做
变形仅在类的定义阶段发生一次 后续再添加的带有双下划线的任何属性都不会变形 就是普通属性class Student: def __init__(self, name, age, gender, id_card): self.name = name self.age = age self.gender = gender self.__id_card = id_card # 封装方法 def __say(self): print('hello') def show_id_card(self): # 可以在这里添加额外的任何逻辑代码 来限制外部的访问 # 在类的内部 可以访问 print(self.__id_card) s = Student('jack',18,'man',32132111) # print(s.__id_card) # 报错内部封装了无法访问 # print(s._Student__id_card) # 通过变形拿到结果32132111 (被封装的属性名其实变成了'_Student__id_card') s.show_id_card() # 32132111 通过函数在类内部访问拿到结果 # s.__id_card = 1233 # print(s.__id_card) # 1233 访问的不是原属性,而是在对象中添加了__id_card print(s.__dict__) # 'name': 'jack', 'age': 18, 'gender': 'man', '_Student__id_card': 32132111, '__id_card': 1233}
五、property装饰器
5.1 伪装成普通属性
作用:将一个方法伪装成普通属性
为什么用property:将访问私有属性和普通属性的方式变得一致
与property相关的 两个装饰器
property
对象点被装饰的方法触发(一般用于获取封装属性的值)setter: 用点语法 给属性赋值时触发 (一般用于设置,给对象设置属性)
deleter: 用点语法删除属性时触发 (一般用于删除属性的值)
class Teacher: def __init__(self,name,salary): self.name = name self.__salary = salary @property # getter 用于能访问私有属性的值,也可以访问普通属性 def salary(self): return self.__salary @salary.setter # 用来设置私有属性的值,也可以设置普通属性 def salary(self,new_salary): self.__salary = new_salary @salary.deleter # 用于删除私有属性的值,也可以删除普通属性的值 def salary(self): del self.__salary t = Teacher("wangyong",12000) print(t.salary) # 12000 t.salary = 15000 print(t.salary) # 15000 del t.salary print(t.salary) # 报错,应被已经被删了,报错原因: AttributeError: 'Teacher' object has no attribute '_Teacher__salary'
5.2 实现计算属性
class Person: def __init__(self,name,height,weight): self.name = name self.height = height self.weight = weight # self.BMI = weight / (height ** 2) @property def BMI(self): return self.weight / (self.height ** 2) @BMI.setter def BMI(self,new_BMI): print("BMI 不支持自定义.....") p = Person("egon",1.7,80) print(p.BMI) p.BMI = 10