1、如何创建可管理的对象属性?
实际案例:
在面向对象编程中,我们把方法(函数)看作对象的接口,直接访问对象的属性可能是不安全的,或设计上不够灵活。但是使用调用方法在形式上不如访问属性简洁。
# 创建圆的类,获得圆的半径或设置圆的半径,需要为这个类添加如下两个方法
# 访问器和设置器形式:
circle.getRadius()
circle.setRadius(5.0) # 繁
# 直接访问形式:
circle.radius
circle.radius = 5.0 # 简
能否在形式上是属性访问,但实际上调用方法?
解决方案:
使用property函数为类创建可以管理属性(方法),fget/fset/fdel对应相应属性访问。
2、代码演示
from math import pi
class Circle(object):
def __init__(self, radius):
# 圆半径
self.radius = radius
def get_radius(self):
# 对半径保留2位小数取四舍五入
return round(self.radius, 2)
def set_radius(self, value):
if not isinstance(value, (int, float)):
raise ValueError('wrong type')
self.radius = float(value)
def get_area(self):
# 获得圆的面积
return self.radius ** 2 * pi
# 3个参数分别对应,访问方法、设置方法、删除方法
R = property(get_radius, set_radius)
c = Circle(3.2)
'''
安全性:
直接访问属性可能会存在问题,在某些时刻用户参数值可能传错了,
传了一个字符串,在逻辑上显然已经错误了半径不可能是字符串,
但是在程序运行上不会有任何错误。因为实例的属性可以是任何类型。
用户并不知道它的逻辑上出现错误,继续做计算结果显示是错误的。
'''
c.radius = 'abc'
d = c.radius * 2
print(d)
'''
逻辑上错了但运行上没有错,这就导致程序出现一些莫名其妙问题。
希望能在赋值的这个点上就知道程序已经出错了,这就是使用方法优势,
使用方法的时候手段就变多了,可以对参数值进行类型检查。
'''
# c.set_radius('abc')
c2 = Circle(3.2)
'''
灵活性:
开始的时候圆的半径总是用户输出什么就返回什么,
后来需求改变了希望用户看到的半径是原来输入的
保留两位小数并且四舍五入结果。
这种情况下如果使用方法这种情况就很好解决,
这里面涉及到一个隐藏,不想让用户看到真实的东西。
'''
# 用户的radius没有变但得到的结果改变了
print(c2.get_radius())
# 使用property函数安全简洁高效调用各个方法
c3 = Circle(3.2)
# 会调用property第1个访问方法get_area
print(c3.R)
# 赋值时候,会调用property第3个设置方法set_radius
c3.R = 5.9
print(c3.R)