Python에서 클래스 속성 캐싱
python으로 수업을 쓰고 있는데 계산에 비교적 오랜 시간이 걸릴 속성이 있어서 한 번만 하고 싶습니다.또한 수업의 모든 인스턴스에서 필요하지 않을 것이기 때문에 기본적으로 하고 싶지 않습니다.__init__
.
저는 파이썬은 처음이지만 프로그래밍은 처음입니다.저는 이것을 꽤 쉽게 할 수 있는 방법을 생각해 낼 수 있지만, 저는 어떤 것을 하는 '파이토닉' 방식이 제가 다른 언어에서 경험을 사용하여 생각해낸 것보다 훨씬 더 간단하다는 것을 반복해서 발견했습니다.
파이썬에서 이를 '올바른' 방법이 있습니까?
3.8 ≤ Python이며 에 결합되었습니다.
import functools
class MyClass:
@functools.cached_property
def foo(self):
print("long calculation here")
return 21 * 2
3.2 ≤ Python < 3.8
및 데코레이터를 모두 사용해야 합니다.
import functools
class MyClass:
@property
@functools.lru_cache()
def foo(self):
print("long calculation here")
return 21 * 2
이 답변에는 더 자세한 예제가 있으며 이전 Python 버전의 백포트도 언급되어 있습니다.
파이썬 < 3.2
Python Wiki에는 다음과 같이 사용할 수 있는 캐시된 속성 장식기(MIT 라이센스)가 있습니다.
import random
# the class containing the property must be a new-style class
class MyClass(object):
# create property whose value is cached for ten minutes
@cached_property(ttl=600)
def randint(self):
# will only be evaluated every 10 min. at maximum.
return random.randint(0, 100)
또는 다른 답변에 언급된 모든 구현이 사용자의 요구에 부합합니다.
또는 위에 언급된 백포트.
나는 예전에 귀재가 제안한 대로 했지만, 결국 작은 살림살이 스텝들에 싫증이 났습니다.
그래서 저는 저만의 설명자를 만들었습니다.
class cached_property(object):
"""
Descriptor (non-data) for building an attribute on-demand on first use.
"""
def __init__(self, factory):
"""
<factory> is called such: factory(instance) to build the attribute.
"""
self._attr_name = factory.__name__
self._factory = factory
def __get__(self, instance, owner):
# Build the attribute.
attr = self._factory(instance)
# Cache the value; hide ourselves.
setattr(instance, self._attr_name, attr)
return attr
사용 방법은 다음과 같습니다.
class Spam(object):
@cached_property
def eggs(self):
print 'long calculation here'
return 6*2
s = Spam()
s.eggs # Calculates the value.
s.eggs # Uses cached value.
일반적인 방법은 속성을 속성으로 만들고 처음 계산할 때 값을 저장하는 것입니다.
import time
class Foo(object):
def __init__(self):
self._bar = None
@property
def bar(self):
if self._bar is None:
print "starting long calculation"
time.sleep(5)
self._bar = 2*2
print "finished long caclulation"
return self._bar
foo=Foo()
print "Accessing foo.bar"
print foo.bar
print "Accessing foo.bar"
print foo.bar
Python 3.8에는 데코레이터가 포함되어 있습니다.
클래스의 메서드를 한 번 계산된 값을 인스턴스 수명에 대한 일반 속성으로 캐시하는 속성으로 변환합니다.와 유사한
property()
캐싱 기능을 추가했습니다.값비싼 계산된 인스턴스의 속성을 계산할 때 유용하며, 그렇지 않으면 효과적으로 변경할 수 없습니다.
다음 예제는 문서에서 직접 가져온 것입니다.
from functools import cached_property
class DataSet:
def __init__(self, sequence_of_numbers):
self._data = sequence_of_numbers
@cached_property
def stdev(self):
return statistics.stdev(self._data)
@cached_property
def variance(self):
return statistics.variance(self._data)
캐시할 속성을 가진 개체가 다음을 가져야 한다는 제한 사항__dict__
변수 매핑인 속성, 클래스 제외__slots__
~하지 않는 한__dict__
에 정의되어 있습니다.__slots__
.
언급했듯이,functools.cached_property
캐시된 인스턴스 특성에 대해 작동합니다.캐시된 클래스 속성의 경우:
from functools import cache
class MyClass:
@classmethod
@property
@cache
def foo(cls):
print('expensive calculation')
return 42
>>> MyClass.foo
expensive calculation
42
>>> MyClass.foo
42
재사용 가능한 데코레이터를 원한다면,
def cached_class_attr(f):
return classmethod(property(cache(f)))
class MyClass:
@cached_class_attr
def foo(cls):
...
3.9 > = 파이썬 < 3.11
패키지(내 패키지가 아님) 제공cachedproperty
,classproperty
그리고.cachedclassproperty
클래스 속성을 캐시하는 방법
from descriptors import cachedclassproperty
class MyClass:
@cachedclassproperty
def approx_pi(cls):
return 22 / 7
class MemoizeTest:
_cache = {}
def __init__(self, a):
if a in MemoizeTest._cache:
self.a = MemoizeTest._cache[a]
else:
self.a = a**5000
MemoizeTest._cache.update({a:self.a})
당신은 메모화를 조사해 볼 수 있습니다.함수에 동일한 인수를 전달하면 캐시된 결과가 반환됩니다.파이썬으로 구현하는 것에 대한 자세한 정보는 여기에서 확인할 수 있습니다.
또한 코드 설정 방법에 따라(모든 인스턴스에서 필요하지 않다고 하는 경우) 플라이웨이트 패턴 또는 레이지 로딩을 사용할 수 있습니다.
현재 응답의 대부분은 캐시 인스턴스 특성에 관한 것입니다.클래스 속성을 캐시하려면 사전을 사용하면 됩니다.이렇게 하면 인스턴스당 한 번이 아니라 클래스당 한 번씩 속성이 계산됩니다.
mapping = {}
class A:
def __init__(self):
if self.__class__.__name__ not in mapping:
print('Expansive calculation')
mapping[self.__class__.__name__] = self.__class__.__name__
self.cached = mapping[self.__class__.__name__]
설명하자면,
foo = A()
bar = A()
print(foo.cached, bar.cached)
기브즈
Expansive calculation
A A
이를 수행하는 가장 간단한 방법은 속성(게터 메서드)을 둘러싸는 메서드를 작성하는 것입니다.이 메서드는 처음 호출할 때 값을 계산하고 저장한 후 반환합니다. 나중에 저장한 값만 반환합니다.
Python 3이 아닌 Python 2로 제가 하는 일은 이렇습니다.이는 다음과 같은 효율성을 제공합니다.
class X:
@property
def foo(self):
r = 33
self.foo = r
return r
例설:는 단지 값으로 기본적으로, 저는 단지 계산된 값으로 속성 메소드를 오버로드하는 것입니다.따라서 속성에 처음 액세스한 후(예:foo
더 이상 속성이 아니며 인스턴스 속성이 됩니다.의 장점은 한 한 입니다.self.__dict__
캐시로 사용되고 있으며 속성을 사용하지 않는 경우 인스턴스 오버헤드가 발생하지 않습니다.
이 접근 방식은 Python 3에서 작동하지 않습니다.
언급URL : https://stackoverflow.com/questions/4037481/caching-class-attributes-in-python
'programing' 카테고리의 다른 글
PowerShell에서 사용자 지정 기능 로드 (0) | 2023.08.10 |
---|---|
도커 파일에서 PYONUNBUFFERED의 용도는 무엇입니까? (0) | 2023.08.05 |
통합 터미널 및 작업에 대해 Visual Studio Code가 갑자기 PowerShell로 기본 설정됨 (0) | 2023.08.05 |
그룹 SQL별 실행 총계(Oracle) (0) | 2023.08.05 |
항목이 없는 경우 오류 없이 존재하는지 확인 (0) | 2023.08.05 |