封装
封装:主要是指在类的定义阶段将,以__开头的属性名进行变形.。例如:__name ==> _People__name
封装的主要特点:
1.在类外部无法直接__name,想要在外部调用可以使用_People__name
2.在类内部可以直接使用__name
3.子类无法覆盖父类__开头的属性
解释特点3的例子:
class Foo: def __func(self): # _Foo_func print('from foo') class Bar(Foo): def __func(self): # _Bar_func print('form bar') b = Bar() b.func()
由上可以看出函数属性名在经过变形之后,子类与父类的函数名不相同,所以子类无法覆盖父类__开头的属性
封装的时候应注意的问题
1.所谓的隐藏并不是真正的隐藏,可以通过_People__name来获取
2.想要隐藏属性,就要在类的定义阶段进行隐藏,只发生一次
3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
解释问题一的例子
class B: __x = 1 print(_B__x)
解释问题二的例子
class B: __x = 1 def __init__(self,name): self.__name = name B.__y = 2 print(B.__dict__) print(B.__y)
第一次打印的是:
{'__module__': '__main__', '_B__x': 1, '__init__': <function B.__init__ at 0x000002412D07BA60>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None, '__y': 2}
由此可以看出想要隐藏属性,只能在类定义的时候进行隐藏
解释问题三的例子
class A: def __foo(self): # _A__foo print('A.foo') def bar(self): print('A.bar') self.__foo() #self._A_foo() class B(A): def __foo(self): # _B__foo print('B.foo') b = B() b.bar()
封装的意义
封装数据属性的意义:明确区分内外,控制外部对的隐藏属性的操作行为
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("年龄必须是整数类型") self.__name = name self.__age = age p = People('yang',18) # p.tell_info() p.set_info('11',19) p.tell_info()
封装函数属性的意义 :隔离复杂度
#二、封装方法,隔离复杂度 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() print(ATM.__dict__) a=ATM() a.withdraw()
property:
@property 主要是将将函数属性伪装成数据属性,是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
- @property 查看 必须要有返回值 print(p.name) name 是函数属性 不是数据属性 伪装成 数据属性
- @name.setter 修改 p.name='alex'
- @name.deleter 删除 del p.name
总结:通过计算得来的方法 可以通过@property 伪装成数据属性
''' 例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 成人的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,height,weight): self.name = name self.weight = weight self.height = height @property def bmi(self): return self.weight / (self.height ** 2) p = People('yang',1.78,61) print(p.bmi) # p.bmi = 33 #报错 class People: def __init__(self,name): self.__name = name @property def name(self): # print('getter') return self.__name @name.setter def name(self,val): # print('setter') if not isinstance(val,str): print('名字必须是字符串类型') return self.__name = val @name.deleter def name(self): print("不可以被删除") p = People('egon') # print(p.get_name()) # p.name = 'EGON' # print(p.name) del p.name