2012-02-14 4 views
5

Comment implémenteriez-vous une charge paresseuse d'attributs d'objet, c'est-à-dire si des attributs sont accédés mais n'existent pas encore, une méthode d'objet est appelée, qui est supposée les charger?Chargement paresseux des attributs

Ma première tentative est

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 

Je ferai lazyload spécifiques à certains noms d'attributs seulement. Comme je n'ai pas encore fait beaucoup de méta-classification, je ne suis pas sûr que ce soit la bonne approche. Que suggérez-vous?

+1

* "Métaclasses sont plus profondes magique Si vous vous demandez si vous avez besoin de 99% des utilisateurs ne devrait jamais se soucier, vous ne le faites pas.. " - TP *. Je pense qu'une propriété telle que suggérée par Daniel serait meilleure. –

+0

J'utilise cette recette http://code.activestate.com/recipes/576563-cached-property/ – reclosedev

+0

@Rik: Je ne me demande pas si j'ai besoin de méta-classes, mais plutôt, comment résoudre le problème de lazyload. L'exemple de Daniels ne le résout pas encore, puisqu'il est en lecture seule et que je ne veux pas de lignes de code en double pour chaque occurrence. Peut-il être ajusté? – Gerenuk

Répondre

6

On dirait un property simple, ferait l'affaire mieux:

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

Semble soigné, mais maintenant la question est de savoir si cela peut être fait pratique? J'ai aussi besoin de propriétés accessibles en écriture. Et plus important encore, est-ce que je peux emballer ceci dans une notation gentille sans réécrire les mêmes 4 lignes de code plusieurs fois? – Gerenuk

+0

Puis-je même écrire 'my_attribute = lazyload (load_method)' dans la définition de classe ou quelque chose de similaire? – Gerenuk