property的作用是将类的方法伪装成属性,将方法伪装成属性有联动、安全、健壮三大优点。以下我们通过案例来详细讲述这三大优点。
一、联动
案例:
class Goods:
def __init__(self, name, price, count=1):
self.name = name # 商品名称
self.price = price # 商品单价
self.count = float(count) # 商品数量
self.total = price*count
apple = Goods('苹果', 5, 2)
print(apple.total)
apple.count = 3
print(apple.total)
out:
10
10
在上述案例中建了一个Goods(商品)类,它有name(商品名称)、price(商品单价)、count(商品数量)。它内部还有个toatl(商品总价)属性,这个属性是根据单价乘数量计算得来的。
接下来建了一个实例:apple,名称是苹果,单价是5,数量是2。现在打印apple.total显示是10,结果正常,可是当我们把数量改成3以后再打印apple.total结果仍然是10,数据没有产生联动!编程的时候一定要避免这样的情况发生。
正解:
class Goods:
def __init__(self, name, price, count=1):
self.name = name # 商品名称
self.price = price # 商品单价
self.count = float(count) # 商品数量
@property
def total(self): # 商品总价
return self.price*self.count
apple = Goods('苹果', 5, 2)
print(apple.total)
apple.count = 3
print(apple.total)
在这段代码中,通过将total方法伪装成属性的方式,我们可以获得联动的total属性。
好了,请记住使用property的第一条优点——数据联动。
二、健壮
继续上述的案例讲健壮,假设商品数量是售货员手动输入的,若遇到售货员不小心将数量输成了’a’会发生什么呢?
class Goods:
def __init__(self, name, price, count=1):
self.name = name # 商品名称
self.price = price # 商品单价
self.count = float(count) # 商品数量
@property
def total(self): # 商品总价
return self.price*self.count
apple = Goods('苹果', 5, 'a')
print(apple.total)
out:
ValueError: could not convert string to float: 'a'
这下程序直接报错,异常退出了!当然你可以指责售货员的不小心,但同时也不能否认自己编写的代码容错率低,也就是不健壮,动不动就报错!合格的程序员编写代码时必须考虑到各种情况,提高程序的健壮性。下面我们针对上述的情况更正代码:
class Goods:
def __init__(self, name, price, count=1):
self.name = name # 商品名称
self.price = price # 商品单价
self.__count = count # 商品数量
@property
def count(self):
try:
self.__count = float(self.__count)
except ValueError:
print('输入数量有误,数值自动修正为1.0,请注意核对!')
self.__count = 1.0
return self.__count
@count.setter
def count(self, n):
try:
n = float(n)
except ValueError:
print('输入数量有误,数值自动修正为1.0,请注意核对!')
n = 1.0
self.__count = n
@property
def total(self): # 商品总价
return self.price*self.count
apple = Goods('苹果', 5, 'a')
print(apple.total)
apple.count = 'bb'
print(apple.total)
out:
输入数量有误,数值自动修正为1.0,请注意核对!
5.0
输入数量有误,数值自动修正为1.0,请注意核对!
5.0
注意@函数名.setter的写法,这个函数名要和前一个@property下一行的函数名要一致。
三、安全
继续上述的代码讲安全,数据安全有一项重要的内容就是确保数据值在合理范围区间,如果不对重要数据进行值范围校验就会发生重大差错。假设上述案例中某营业员将销售数量改成负数会发生什么?显而易见的会发生账目差错,所以我们要对count数值进行校验,不能接受负数。
因此必须修改@count.setter部分:
@count.setter
def count(self, n):
try:
n = float(n)
if n < 0:
print('输入数量有误,数值自动修正为0,请注意核对!')
n = 0
except ValueError:
print('输入数量有误,数值自动修正为1.0,请注意核对!')
n = 1.0
self.__count = n
最后补充一下property的deleter部分,它可以在调用del apple.count时删除__count属性:
@count.deleter
def count(self):
del self.__count
总结
property有三部分内容:
@property是装饰器,可以用来将类中的方法伪装成属性;
@方法名.setter也是装饰器,在修改伪装成属性的方法值时会调用它;
@方法名.deleter还是装饰器,在删除伪装成属性的方法值时会调用它。
property有三大优点:
合理地使用property可以提高程序的联动、健壮、安全。