pydata

Keep Looking, Don't Settle

python class (5): 使用装饰器@property来设定属性

python中有时候需要对定义的属性/方法添加一些限制,或者进行一些运算。比如定义一个圆,给定半径,那么直径和面积都会随之而定。

下面这个例子是在SF python meetup上Simeon Franklin给的一个小作业

"""
Properties let us intercept attribute access, sneaking in a function
call where it looks like we merely lookup or set an attribute on an
object.

The Circle class below is broken: its constructor takes a radius
argument

>>> c = Circle(10)

and calculates the diameter

>>> c.diameter
20

But what if you changed the radius? Now the diameter would be incorrect!

Fix the class so that the diameter and radius are kept in sync.

>>> c.radius = 5
>>> c.diameter
10
>>> c.diameter = 12
>>> c.radius
6

"""
import math

class Circle(object):
    def __init__(self, radius):
        self._radius = radius
        self._diameter = 2 * radius
        self._area = math.pi * radius ** 2

    #定义radius的属性,由radius怎么来求出diameter和area
    @property
    def radius(self):
        return self._radius
    #让这个属性可写,如果没有下面的@.setter,那么radius就是一个只读属性
    @radius.setter
    def radius(self, radius):
        self._radius = radius
        self._diameter = 2 * radius
        self._area = math.pi * radius ** 2

    #同样,定义一个diameter属性,以及怎么由此求出半径和面积
    @property
    def diameter(self):
        return self._diameter
    @diameter.setter
    def diameter(self, diameter):
        self._diameter = diameter
        self._radius = diameter / 2
        self._area = math.pi * (diameter / 2) ** 2

    #给定面积求出相应的半径和直径
    @property
    def area(self):
        return self._area
    @area.setter
    def area(self, area):
        self._area = area
        self._radius = math.sqrt( area / math.pi)
        self._diameter = 2 * math.sqrt( area / math.pi)

#如果只有@property而没有对应的@.setter属性,那就是定义了一个只读的属性