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)
Selon la méthode d'implémentation de memoized_property, les réponses suivantes ont toutes une prémisse, c'est-à-dire qu'il est supposé qu'elle est utilisée comme décorateur pour les fonctions de classe. À ce stade, cette classe peut être considérée comme une version modifiée du décorateur de propriétés. L'effet de mise en cache peut être obtenu car Python a la priorité lors de l'accès aux attributs .
Pour
a.val
, Python effectue le traitement suivant :accède d'abord au
__dict__
de l'objet, c'est-à-direa.__dict__['val']
;A.__dict__['val']
;du descripteur sera appelée
A.__dict__['val']
__get__
;memoized_property
Par exemple, cette classe encapsule la fonction val de la classe A :Lors du premier accès à
, selon la séquence de recherche ci-dessus : il n'est pas trouvé dans l'objet, passez à la deuxième étape, il est trouvé dans le dictionnaire de classe, mais il s'agit d'un descripteur ; , il entrera donc le descripteur dans la méthode. Ici, après avoir utilisé
c'est très clair, il suffit de supprimer le chemin avec la priorité précédente. Ensuite, Python a dû rechercher étape par étape la priorité et a découvert queval
pour appeler la fonction décorée__get__
et calculer le résultat, tout en renvoyant le résultat, le résultat est également stocké dansself.fget(obj)
. La prochaine fois que vous visiterezval
, puisque leobj.__dict__['val']
de l'objet contienta.val
, il recherchera__dict__
d'abord au lieu de tout mettre en œuvre pour trouverval
. Cela permet d'obtenir l'effet de mettre en cache un attribut. Le généralobj.__dict__['val']
ne réglera pas__get__
, il sera donc recalculé à chaque fois.__get__
obj.__dict__['xxx']
Après avoir compris cela,était disponible, il a donc appelé la méthode
peut être considéré comme bien meilleur. . . .reset
et l'a recalculée à nouveau.__get__
a.val
Et l'intérieur deUne méthode de classe est une méthode que vous pouvez appeler directement sans instancier la classe