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)
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__
클래스 메서드는 클래스를 인스턴스화하지 않고 직접 호출할 수 있는 메서드입니다