Кэшировать результаты свойств в python через декоратор - PullRequest
0 голосов
/ 27 января 2020

В моем сценарии у меня есть класс со многими свойствами. Свойства не принимают никаких параметров, они тяжелы во времени вычислений, и их результаты не должны изменяться в течение жизненного цикла программы.

Я хочу кешировать результаты этих свойств, поэтому тяжелый расчет выполняется только один раз. Подход, который я выбрал, заключается в использовании декораторов:

def cached(f):
    def wrapper(*args):
        # get self
        class_self = args[0]
        cache_attr_name = '_' + f.__name__

        if hasattr(class_self, cache_attr_name):
            return getattr(class_self, cache_attr_name)

        else:
            result = f(*args)
            setattr(class_self, cache_attr_name, result)
            return result

    return wrapper

, а затем в кэшированных членах класса:

class MyClass():
    @property
    @cached
    def heavy_prop(self):
        # In the actual class, the heavy calculation happens here
        return 1

Есть идеи для лучшего / другого решения для этого случая?

1 Ответ

2 голосов
/ 27 января 2020

Для Python 3.8 используйте встроенную cached_property: https://docs.python.org/dev/library/functools.html#functools .cached_property

Для более старых версий используйте библиотеку https://github.com/pydanny/cached-property

Или просто используйте этот код:

class cached_property(object):
    """
    A property that is only computed once per instance and then replaces itself
    with an ordinary attribute. Deleting the attribute resets the property.

    Based on https://github.com/pydanny/cached-property/blob/master/cached_property.py
    """

    def __init__(self, func):
        self.__doc__ = func.__doc__
        self.func = func

    def cached_property_wrapper(self, obj, _cls):
        if obj is None:
            return self

        value = obj.__dict__[self.func.__name__] = self.func(obj)
        return value

    __get__ = cached_property_wrapper
...