面向对象-封装实现属性隐藏
封装原理与特性
隐藏属性:在变量或函数前面加__符号
class A: __x=1 def __init__(self,name): self.__name=name def __foo(self): print('run foo') print(A.__x)
print(A.__dict__)
在类定义阶段就,已经改名字。即检测语法的时候已经变形。
在类的内部可以直接调用
class A: __x=1 def __init__(self,name): self.__name=name def __foo(self): print('run foo') def bar(self): self.__foo() print('from bar') a=A('ya') a.bar()
正常情况下,子类可以重写父类方法
class Foo: def func(self): print("from foo") class Bar(Foo): def func(self): print('from foo') b=Bar() b.func()
但是父类方法隐藏后,子类无法重写父类方法
class Foo: def __func(self): print("from foo") class Bar(Foo): def __func(self): print('from foo') b=Bar() b.func()
变形特点
- 在类的外部无法直接通过obj.__AttrName来访问
- 在类的内部可以直接使用obj.__AttrName来访问
- 子类无法重写父类方法,即子类无法覆盖父类__开头的属性
变形注意的问题:
- 这种隐藏不是真正的隐藏
- 变形在类定义阶段发生,定义后再给类添加隐藏属性,则无法达到‘隐藏’效果
- 在继承中,如果父类不想子类重写方法,可用__设置称私有的,使其无法修改
封装的意义
封装数据属性:明确区分内外,在内部定义接口,使其外部间接访问,也可定义修改接口,可以在接口上添加逻辑,进行控制。
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)) p=People('ya',18) p.tell_info()
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('ya',18) p.tell_info() p.set_info('Hyaya','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() a=ATM() a.withdraw()
类外部用户无需单独一步一步执行__方法,只需调用withdraw()方法即可
封装与扩展
class Room: def __init__(self,name,owner,height,weight,length): self.name=name self.owner=owner #将长宽高设置为隐藏 self.__height=height self.__weight=weight self.__length=length def tell_area(self): return self.__weight * self.__length r=Room('卫生间','xxx',10,10,10) print(r.tell_area())
用户可以随意修改tell_area()方法,对于用户的调用,无需干涉。
property的使用
把通过计算才能获得值得方法封装称属性方式,调用无需添加()符号
装饰后,调用数据属性的方式调用方法属性,但是不可直接像数据属性一样赋值
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('egon',80,1.6) print(p.bmi)
p=People('egon',80,1.6) p.bmi=22 print(p.bmi)
对方法属性再次控制
class People: def __init__(self,name): self.__name=name @property def name(self): return self.__name @name.setter def name(self,val): if not isinstance(val,str): print(("名字必须为字符串")) return self.__name=val @name.deleter def name(self): print('名字属性不让删除') p=People('ya') p.name="YA" print(p.name) del p.name