封装之如何调用隐藏属性
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
class A: __x = 1 # 在类定义阶段,变量名发生了变形,变为:_类名__x(_A__x = 1) def __init__(self,name): self.__name = name # self._A__name=name def __foo(self): # def _A__foo(self): print("run foo") def bar(self): self.__foo() # 在定义阶段,已将代码变为self._A__foo(): print("from bar") a = A("egon") # print(a.__name) a.bar() # 在类内部可以调用 a._A__foo()
这种变形的特点:
1、类的外部无法直接访问obj.__AttrName
2、在类内部是可以直接使用obj.__AttrName(在定义阶段已经改成_obj.__AttrName)
3、子类无法覆盖隐藏的属性(__开头)
class Foo: def func(self): print("from foo") class Bar(Foo): def func(self): print("from bar") # b = Bar() # b.func()
子类无法覆盖父类的隐藏属性的原因
class Foo: def __func(self): # _Foo__func print("from foo") class Bar(Foo): def __func(self): #_Bar__func print("from bar")
这种变形需要注意的问题是:
1、这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
2、变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形
3、在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
封装的意义
一、封装数据属性:明确的区分内外(在类内部开一个接口,调用隐藏的内容),控制外部对隐藏属性的操作
class People: def __init__(self,name,age): self.__name = name self.__age = age def tell_info(self): print("name:%s,age:%s"%(self.__name,self.__age)) def set_info(self,name,age): if not isinstance(name,str): print("名字必须是字符串类型") return if not isinstance(age,int): print("年龄必须是数字类型") return self.__name = name self.__age = age p = People("alex",15) p.tell_info() p.set_info(123,22)
二、封装方法:隔离复杂度
class ATM: def __card(self): print('插卡') def __auth(self): print('用户认证') def __input(self): print('输入取款金额') def __print_bill(self): print('打印账单') def __take_money(self): print('取款') def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a=ATM() a.withdraw() # 对外无需知道内部具体的流程
封装体现可扩展性
class Room: def __init__(self,name,owner,weight,length,height): self.name = name self.owner = owner self.__weight = weight self.__length = length self.__height = height def tell_area(self): return self.__weight * self.__length * self.__height r = Room("卫生间","alex",10,10,10) print(r.tell_area())
property
通过计算才能得到的一些属性封装起来,让用户访问起来像访问数据一样,而不是像访问属性(带())形式
例如:
"""
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
"""
class People: def __init__(self,name,weight,height): self.name = name self.weight = weight self.height = height @property # 调用时不用加() def bmi(self): return self.weight / (self.height ** 2) p = People("alex",75,1.81) # p.bmi = p.weight / (p.height ** 2) print(p.bmi) # p.bmi 本质是一种方法 p.height = 1.82 print(p.bmi)
例中的p.bmi不能被赋值,若硬要赋值
class People: def __init__(self,name): self.__name = name @property def name(self): print("getter") return self.__name @name.setter # 修改 必须前面被装饰器property装饰过的 def name(self,val): print("setter",val) if not isinstance(val,str): print("名字必须是字符串类型") return self.__name = val @name.deleter # 删除 必须前面被装饰器property装饰过的 def name(self,val): print("delete") print("不允许删除") p = People("alex") p.name p.name = "Jack" # 硬要赋值的话用@函数名.setter print(p.name)