2012-02-14 104 views
5

如何实现对象属性的延迟加载,即如果属性被访问但尚不存在,某些对象方法被调用,应该加载这些属性?延迟加载属性

我第一次尝试是

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 *。我认为丹尼尔建议的财产会更好。 – 2012-02-14 10:58:05

+0

我正在使用这个食谱http://code.activestate.com/recipes/576563-cached-property/ – reclosedev 2012-02-14 14:56:57

+0

@Rik:我不是在想我是否需要元类,而是如何解决lazyload问题。 Daniels的例子还没有完全解决它,因为它是只读的,我不希望每次出现重复的代码行。它可以调整吗? – Gerenuk 2012-02-15 09:44:43

回答

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 2012-02-14 16:14:30

+0

我可以在类定义或类似的东西中写'my_attribute = lazyload(load_method)'吗? – Gerenuk 2012-02-14 16:28:19