封装之如何隐藏属性
在python中用双下划线开头的方式设置属性将属性隐藏起来(设置成私有的),以双下划线开头且双下划线结尾的是python的内置方法。
# 其实这仅仅这是一种变形操作 # 类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式: class A: __N=0 # 类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的,如__N,会变形为_A__N def __init__(self): self.__X=10 # 变形为self._A__X def __foo(self): # 变形为_A__foo print('from A') def bar(self): self.__foo() # 只有在类内部才可以通过__foo的形式访问到. # A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
这种变形的特点:
- 在类外部无法直接 A.__N
- 在类内部是可以直接使用:A.__N
- 子类无法覆盖父类 __ 开头的属性
- 变形只在定义类里面发生,在类外面定义是不会发生变形的
# 带 __ 的属性名,父类与子类中属性名字不同,所以不存在覆盖一说 class Foo: def __func(self): # _Foo__func print('from foo') class Bar(Foo): def __func(self): # _Bar__func print('from bar')
如果子类里面有和父类的同名属性,想使用父类里的属性,不想被覆盖,把父类里的同名属性前加上 __ , 在另一个属性内进行调用。
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): # isinstance(m,n) m是n的实例 print('名字必须是字符串类型') return if not isinstance(age, int): print('年龄必须是数字类型') return self.__name = name self.__age = age p = People('egon', 18) 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 with_draw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money() a = ATM() a.with_draw()
封装与可扩展性
class Room: def __init__(self, name, owner, weight, length): self.name = name self.owner = owner self.__weight = weight self.__length = length def tell_area(self): return self.__weight * self.__length r = Room('卫生间', 'alex', 10, 10) print(r.tell_area()) # 对于用户来说,只需记住tell_area()方法来获取所需信息即可,对于开发者,可自行改变输出结果的计算方法
什么是特性property
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
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, weight, height): self.name = name self.weight = weight self. height = height @property def bmi(self): return self.weight / (self.height ** 2) p = People('egon', 75, 1.81) # p.bmi = p.weight / (p.height ** 2) # print(p.bmi()) print(p.bmi) # 有了property,使用者可以像调用数据一样调用属性,所以这个方法必须有返回值
补充:
class People: def __init__(self, name): self.__name = name @property def name(self): return self.__name @name.setter # 已经被 property 装饰过的函数可以被重新调用使用 def name(self, val): if not isinstance(val, str): print('名字必须是字符串类型') return self.__name = val @name.deleter def name(self): print('不允许删除') p = People('egon') p.name # 这是个访问行为,触发property装饰的 p.name = 'Egon' # 这是个修改行为,触发name.setter装饰的 del p.name # 这是个删除行为,触发name.deleter装饰的