Кэширует ли @ properties decorator результаты?



Моя IDE имеет"исправленный" мой код для преобразования функции (и другого кода) в свойство. Я беспокоюсь, что это может быть неэффективно.



@property
def output_all_children(self):
lh = ListHolder()
traverse_directories(self.start_directory, lh)
return lh.internal_list


Это делает некоторый тяжелый подъем ввода / вывода и занимает некоторое время. Я задаюсь вопросом, является ли это неправильным из-за соображений эффективности. Мне интересно, не кэшируются ли результаты,как я надеялся.



Если к этому свойству обращаться несколько раз, оно будет перестраиваться и возвращать lh.internal_list каждый раз?
Я бы поправил это путем наличия переменной уровня класса и обновления ее при самостоятельной работе.изменен каталог start_directory.



Я посмотрел на это:
Как создать декоратор для ленивой инициализации свойства и он ссылается на свойство только для чтения, в то время как мое было бы обновленным свойством



Пожалуйста, никаких комментариев по поводу слепого доверия Идам. Я знаю, и это мышление подсказало мне этот вопрос.
448   2  

2 ответов:

Нет, свойство просто преобразует доступ к атрибуту в вызов функции. Автоматическое кэширование не происходит.

Другими словами, синтаксис instance.output_all_children переводится в instance.output_all_children() для вас.

Вы можете легко добавить некоторое кэширование к методу свойств или повторно использовать код, на который вы ссылаетесь в своем вопросе; просто замените метод __set__ для обработки присвоения атрибутов, если вы этого хотите.

Добавление кэширования:

_output_all_children = None

@property
def output_all_children(self):
    if self._output_all_children is None:
        lh = ListHolder()
        traverse_directories(self.start_directory, lh)
        self._output_all_children = lh.internal_list
    return self._output_all_children

Действительно, свойство будет вызываться каждый раз. Это не очень хорошее использование свойства; вызывающие ожидают, что оно займет не намного больше времени, чем доступ к атрибуту.

В пирамиде есть прекрасный декоратор под названием reify, который вызывает функцию в первый раз, а затем устанавливает значение в качестве одноименного атрибута для объекта, чтобы в следующий раз использовалось ранее вычисленное значение.

Если вы не хотите использовать пирамиду только для одного декоратора, вы можете использовать эту версию, которую я написал (it работает как пирамида, но я написал его самостоятельно):

import functools

def reify(func):

    class Descriptor(object):
        def __get__(self, inst, type=None):
            val = func(inst)
            setattr(inst, func.__name__, val)
            return val

    return functools.wraps(func)(Descriptor())

Чтобы он хорошо работал с вашим вариантом использования, просто del атрибут из экземпляра, когда вам нужно его пересчитать:

@reify
def all_children(self):
    lh = ListHolder()
    traverse_directories(self.start_directory, lh)
    return lh.internal_list

# for internal use only, call when a cached all_children may no longer be valid
def _invalidate_all_children(self):
    try:
        del self.all_children
    except AttributeError:
        pass

Comments

    Ничего не найдено.