# -*- encoding: utf-8 -*-
import weakref
'''
第31条: 用描述符来该写需要复用的@property方法
关键:
1 @property
缺点: 不便于复用,受它修饰的方法无法被同一个类中其他属性复用,
与之无关的类也无法复用这些方法
2 描述符
描述符类: 可以提供__get__和__set__方法
原理:
exam.writingGrade = 40
会被转换为
Exam.__dict__['writingGrade'].__set__(exam, 40)
获取属性会被转换为
Exam.__dict__['writingGrade'].__get__(exam, Exam)
之所以存在上述转换: 是因为object类的__getattribute__方法
类实例没有某个属性 ---> 在类中查找同名属性(
类属性,如果实现了__get__和__set__方法,则认为该对象遵循描述符协议)
3 weakref
含义:提供WeakKeyDictionary的特殊字典
特点:如果运行系统发现这种字典所持有的引用是整个程序里面执行Exam
实例的最后一份引用,那么系统就会将实例从字典的键中移除。
4 总结
1) 复用@property方法及其验证机制,用自己定义描述符类
2) WeakKeyDictionary保证描述符类不会泄露内存
参考:
Effectiv Python 编写高质量Python代码的59个有效方法
'''
# class Grade(object):
# def __init__(self):
# self._value = 0
#
# def __get__(self, instance, instance_type):
# return self._value
#
# def __set__(self, instance, value):
# if not (0 <= value <= 100):
# raise ValueError('Grade must be between 0 and 100')
# self._value = value
class Grade(object):
def __init__(self):
self._values = weakref.WeakKeyDictionary()
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):
mathGrade = Grade()
writingGrade = Grade()
scienceGrade = Grade()
def useExam():
exam = Exam()
exam.writingGrade = 82
exam.scienceGrade = 99
print exam.writingGrade
print exam.scienceGrade
secondExam = Exam()
secondExam.writingGrade = 75
print "First writing grade: {value}".format(
value=exam.writingGrade
)
print "Second writing grade: {value}".format(
value=secondExam.writingGrade
)
def process():
useExam()
if __name__ == "__main__":
process()