property

访问属性时,需要表现某种行为时用@property


class T(object):

    def __init__(self):
        self._value = 5 

    @property                  # 最小惊讶原则
    def value(self):           # 列如
        print("Get value")     # getter里面不应该修改属性
        return self._value     # getter, setter 不应该做复杂或缓慢的操作

    @value.setter
    def value(self, value):
        print("Change value")
        self._value = value


t = T() 
print(t.value)
t.value = 10
print(t.value)

当@propety要复用时,用描述符来改写


from weakref import WeakKeyDictionary


class Grade(object):

    def __init__(self):    
        self._values = WeakKeyDictionary() 

        # 用字典来记录每个实例的状态。
        # 为了避免实例引用计数无法降为0, 
        # 垃圾回收器无法回收,这里用弱引用字典。

    def __get__(self, instance, instance_type):
        if instance is None:
            return self
        return self._values.get(instance, 0)

    def __set__(self, instance, value):
        if not (0 <= value <= 100):
            raise ValueError("Grade must be between 0 and 100")
        self._values[instance] = value


class Exam(object):
    math = Grade()
    english = Grade()


exam = Exam()         
exam.math = 97        # Exam.__dict__['math'].__set__(exam, 40) 
exam.english = 89
print(exam.math)      # Exam.__dict__['math'].__get__(exam, Exam)
print(exam.english)
exam.english = 87
print(exam.english)

# 97
# 89
# 87