# -*- 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()