def test_simple(): class A(object): def __init__(self): self.a = 12 self.b = 13 self.counter = 0 def compute(self): try: return self.__dict__['c'] except KeyError: self.counter += 1 self.__dict__['c'] = result = self.a * self.b return result def __getattr__(self, attr): if attr == "c": return self.compute() else: raise AttributeError a = A() assert a.counter == 0 assert a.c == 12 * 13 assert a.counter == 1 assert a.c == 12 * 13 assert a.counter == 1 class B(object): def __init__(self): self.a = 12 self.b = 13 self.counter = 0 def compute(self): self.counter += 1 return self.a * self.b c = LazyAttribute(compute, "c") b = B() assert b.counter == 0 print b.__dict__ assert b.c == 12 * 13 assert b.counter == 1 print b.__dict__ assert b.c == 12 * 13 assert b.counter == 1 b2 = B() b2.a = 100 assert b2.c == 1300 class LazyAttribute(object): def __init__(self, computer, attr): self.computer = computer self.attr = attr def __get__(self, inst, cls): try: return inst.__dict__[self.attr] except KeyError: inst.__dict__[self.attr] = result = self.computer(inst) return result