在面向对象编程中,我们把方法(函数)看作对象的接口。直接访问对象的属性可能是不安全的,或导致设计上不够灵活,但是使用调用方法在形式上不如访问属性简洁。例如:
circle.get_radius() #调用方法 circle.set_radius(5.0) #繁 circle.radius #访问属性 circle.redius = 5.0 #简
要求:实现在形式上是访问属性,实际上内部调用方法。
解决方案:
使用内置的property()
函数为类创建可管理属性,fget/fset/fdel对象属性访问/设置/删除。
- 对于
property()
函数:
property(fget=None, fset=None, fdel=None, doc=None)
返回property属性。fget是获取属性值的函数。fset是用于设置属性值的函数。fdel是用于删除属性值的函数。并且doc为属性对象创建文档字符串。
class C: def __init__(self): self._x = None def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x x = property(getx, setx, delx, "I'm the 'x' property.")
如果c是C的实例,c.x
将调用getter方法获取属性,c.x = value
将调用setter方法设置属性,del c.x
将调用deleter方法删除属性。
如果给出doc,doc将成为该property属性的文档字符串,否则该property将拷贝fget的文档字符串(如果存在)。
此外,如果property()
函数只定义fget(getter),则定义的属性为只读属性。
- 方案示例:
import mathclass Circle: def __init__(self, radius): self.radius = radius def get_radius(self): return round(self.radius, 1) def set_radius(self, radius): if not isinstance(radius, (int, float)): raise TypeError('wrong type') self.redius = radius @property # def get_area(self): def S(self): return round(self.radius ** 2 * math.pi, 1) @S.setter # def set_area(self, s): def S(self, s): self.radius = math.sqrt(s / math.pi) R = property(get_radius, set_radius)c = Circle(5.712)c.R = 100.987print(c.R * 2)c.S = 99.88print(c.S, c.R, end=' ')11.4 #结果99.9 5.6
通过property()
函数定义属性R,来调用get_radius()
和set_radius()
方法。通过@property
装饰器装饰S,达到与定义R属性一样的效果。