class memoized_property(object):
"""A read-only @property that is only evaluated once."""
def __init__(self, fget, doc=None):
self.fget = fget
self.__doc__ = doc or fget.__doc__
self.__name__ = fget.__name__
# 这个方法应该是这个缓存装饰器的关键
# 因此, 我组织关键字如下
# * python __get__
# * how python __get__ works
# # python descript tools
def __get__(self, obj, cls):
if obj is None:
return self
obj.__dict__[self.__name__] = result = self.fget(obj)
return result
def _reset(self, obj):
memoized_property.reset(obj, self.__name__)
@classmethod
def reset(cls, obj, name):
obj.__dict__.pop(name, None)
Menurut kaedah pelaksanaan memoized_property, jawapan berikut semuanya mempunyai premis, iaitu, diandaikan ia digunakan sebagai penghias untuk fungsi kelas. Pada ketika ini kelas ini boleh dianggap sebagai versi pengubahsuaian penghias hartanah. Kesan caching boleh dicapai kerana Python mempunyai keutamaan apabila mengakses atribut .
Untuk
a.val
, Python melakukan pemprosesan berikut:mula-mula mengakses
__dict__
objek, iaitu,a.__dict__['val']
;
ditemui dan nilai dikembalikan, maka nilai itu diperoleh; jika deskriptor dikembalikan, kaedahA.__dict__['val']
JikaUntuk
Sebagai contoh, kelas ini merangkum fungsi val kelas A:A.__dict__['val']
di sini:__get__
buat kali pertama, mengikut urutan carian di atas: ia tidak ditemui dalam objek, lompat ke langkah kedua; ia ditemui dalam kamus kelas, tetapi ia didapati sebagai deskriptor , jadi ia akan memasukkan deskriptor dalam kaedah
untuk memanggil fungsimemoized_property
. Di sini, selepas menggunakanyang dihias dan mengira hasilnya, sambil mengembalikan hasilnya, hasilnya juga disimpan dalam
. Pada kali seterusnya anda melawat, memandangkan terdapat
Dan bahagian dalamval
dalam__get__
objek, ia akan mencariself.fget(obj)
terlebih dahulu dan bukannya berusaha habis-habisan untuk mencarival
. Ini mencapai kesan cache atribut.obj.__dict__['val']
am tidak akan menetapkana.val
, jadi ia akan dikira semula setiap kali.__dict__
val
Selepas memahami perkara ini,obj.__dict__['val']
ia sangat jelas, cuma alih keluar laluan dengan keutamaan sebelumnya. Kemudian Python terpaksa mencari langkah demi langkah di sepanjang keutamaan dan mendapati bahawa__get__
tersedia, jadi ia memanggil kaedah__get__
di dalamnya dan mengira semula sekali lagi.obj.__dict__['xxx']
boleh dikatakan jauh lebih baik. . . .
reset
Kaedah kelas ialah kaedah yang anda boleh panggil terus tanpa membuat seketika kelas