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)
PHP中文网2017-04-18 10:35:42
memoized_property의 구현 방법에 따르면 다음 답변은 모두 전제가 있습니다. 즉, 클래스 함수의 데코레이터로 사용된다고 가정합니다. 이때 이 클래스는 속성 데코레이터의 변형 버전이라고 볼 수 있다. 파이썬이 속성에 접근할 때 우선순위를 가지기 때문에 캐싱 효과를 얻을 수 있습니다.
a.val
의 경우 Python은 다음 처리를 수행합니다.
은 먼저 개체의 __dict__
, 즉 a.__dict__['val']
이 없으면 상속 관계를 따라 위쪽으로 검색합니다.
A.__dict__['val']
A.__dict__['val']
__get__
의 경우:
처음으로 memoized_property
에 접근할 때 위의 검색 순서에 따라: 객체에서 발견되지 않고, 두 번째 단계로 점프하여 클래스 사전에서 발견되지만 디스크립터로 발견됩니다. 이므로
를 이용해 데코레이팅된
함수를 호출해 결과를 계산한 뒤, 결과를 반환하면서 결과도에 저장한다. 다음에 val
을 방문할 때 개체의 __get__
에 self.fget(obj)
이 포함되어 있으므로 val
을 찾기 위해 모든 노력을 기울이는 대신 obj.__dict__['val']
을 먼저 검색합니다. 이는 속성을 캐싱하는 효과를 얻습니다. 일반 a.val
에서는 __dict__
을 설정하지 않으므로 매번 다시 계산됩니다. val
obj.__dict__['val']
이것을 이해하고 나면__get__
아주 명확합니다. 이전 우선순위가 있는 경로를 제거하면 됩니다. 그런 다음 Python은 우선순위에 따라 단계별로 검색해야 했고 __get__
이 사용 가능하다는 것을 알았으므로 그 안에서 obj.__dict__['xxx']
메서드를 호출하고 다시 계산했습니다.
그리고 reset
인테리어도 훨씬 좋아졌다고 할 수 있죠. . . . __get__