2012-02-14 2 views
5

Как реализовать ленивую нагрузку атрибутов объекта, то есть, если доступ к атрибутам отсутствует, но еще не существует, вызывается какой-то метод объекта, который должен их загрузить?Lazy loading атрибутов

Моя первая попытка

def lazyload(cls): 
    def _getattr(obj, attr): 
     if "_loaded" not in obj.__dict__: 
      obj._loaded=True 
      try: 
       obj.load() 
      except Exception as e: 
       raise Exception("Load method failed when trying to access attribute '{}' of object\n{}".format(attr, e)) 
      if attr not in obj.__dict__: 
       AttributeError("No attribute '{}' in '{}' (after loading)".format(attr, type(obj))) # TODO: infinite recursion if obj fails 
      return getattr(obj, attr) 
     else: 
      raise AttributeError("No attribute '{}' in '{}' (already loaded)".format(attr, type(obj))) 

    cls.__getattr__=_getattr 
    return cls 

@lazyload 
class Test: 
    def load(self): 
     self.x=1 

t=Test()  # not loaded yet 
print(t.x) # will load as x isnt known yet 

Сделаю LazyLoad только применительно к определенным именам атрибутов. Как я еще не сделал много метаклассирования, я не уверен, что это правильный подход. Что бы вы предложили?

+1

* "Метаклассы глубже магии, чем 99% пользователей никогда не должны беспокоиться о том случае, если вам интересно, нужно ли вам их, вы не знаете.. " - TP *. Я думаю, что свойство, предложенное Даниэлем, было бы лучше. –

+0

Я использую этот рецепт http://code.activestate.com/recipes/576563-cached-property/ – reclosedev

+0

@Rik: Я не думаю, нужны ли мне метаклассы, а как решить проблему с lazyload. Пример Daniels еще не совсем решает его, поскольку он доступен только для чтения, и я не хочу дублировать строки кода для каждого события. Можно ли отрегулировать? – Gerenuk

ответ

6

Похоже простой property будет делать трюк лучше:

@property 
def my_attribute(): 
    if not hasattr(self, '_my_attribute'): 
     do_expensive_operation_to_get_attribute() 
    return self._my_attribute 
+1

Звучит аккуратно, но теперь вопрос в том, можно ли сделать его удобным? Мне также нужны доступные для записи свойства. И что еще более важно, могу ли я упаковать это в хорошую нотацию, не переписывая те же 4 строки кода много раз? – Gerenuk

+0

Могу ли я написать 'my_attribute = lazyload (load_method)' в определении класса или что-то подобное? – Gerenuk