属性代理
属性代理是指通过@property描述符装饰器来规定用户对类或者实例中某一属性的操作做出行为限制的方式。
类似于JavaScript中的代理器,Vue中的计算属性等,Python中则称之为描述符。
计算获取
BMI指数是用来衡量一个人的体重与身高对健康影响的一个指标,计算公式为:
BMI指数计算公式: BMI = 体重(kg) / (身高m**2)
BMI正常值在20至25之间,超过25为超重,30以上则属肥胖
身高或体重是不断变化的,因而每次想查看BMI值都需要通过计算才能得到,但很明显BMI听起来更像是一个特征而非功能。
为此Python专门提供了一个装饰器@property,可以将类中的方法伪装成属性,对象在访问该特殊属性时会触发功能的执行,然后将返回值作为本次访问的结果,例如:
class Person:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
@property
def bmi(self):
v = self.weight / (self.height ** 2)
if 20 < v < 25:
return "normal"
if v > 25:
return "overweight"
return "obesity"
if __name__ == "__main__":
instanceObject = Person("ken", height=1.76, weight=77)
# autoRun instanceObjectMethod => bmi(self=instanceObject)
print(instanceObject.bmi)
# normal
行为控制
你也可以使用其他的形式,来控制属性的删改查等行为,如下所示:
class Person:
def __init__(self):
self.__attr = None
@property
def name(self):
"""获取name时自动触发该方法,只有当__attr不为None才能被获取到"""
if not self.__attr is None:
return self.__attr
else:
raise AttributeError("name is not set")
@name.setter
def name(self, params):
"""设置name时自动触发该方法,只有当params为 'Jack' 时才能成功为__attr赋值"""
if params != "Jack":
raise AttributeError("name must setting is string 'Jack', but you set is %s"%params)
else:
self.__attr = params
@name.deleter
def name(self):
"""删除name时自动触发该方法,不允许删除name"""
raise AttributeError("name not should delete")
if __name__ == "__main__":
instanceObject = Person()
instanceObject.name = "Jack"
print(instanceObject.name)
del instanceObject.name
# Jack
# AttributeError: name not should delete
行为控制
行为控制还有另外一种形式,它是固定的用法,如下所示,效果和上面一样:
class Person:
def __init__(self):
self.__attr = None
def nameGet(self):
"""获取name时自动触发该方法,只有当__attr不为None才能被获取到"""
if not self.__attr is None:
return self.__attr
else:
raise AttributeError("name is not set")
def nameSet(self, params):
"""设置name时自动触发该方法,只有当params为 'Jack' 时才能成功为__attr赋值"""
if params != "Jack":
raise AttributeError("name must setting is string 'Jack', but you set is %s"%params)
else:
self.__attr = params
def nameDelete(self):
"""删除name时自动触发该方法,不允许删除name"""
raise AttributeError("name not should delete")
name = property(fget=nameGet, fset=nameSet, fdel=nameDelete)
if __name__ == "__main__":
instanceObject = Person()
instanceObject.name = "Jack"
print(instanceObject.name)
del instanceObject.name
# Jack
# AttributeError: name not should delete