File: decorator2.py
""" Class decorator that prints a trace message for every access to an instance's attributes made from outside the class's methods; access within methods proceeds normally without trace """ def Tracer(aClass): # on @decorator class Wrapper: def __init__(self, *args, **kargs): # on instance creation self.wrapped = aClass(*args, **kargs) # use enclosing scope name def __getattr__(self, attrname): print 'Trace:', attrname # catches all but .wrapped return getattr(self.wrapped, attrname) # delegate to wrapped obj return Wrapper """ class Tracer: def __init__(self, aClass): # on @decorator self.aClass = aClass # use instance attribute def __call__(self, *args): # on instance creation self.wrapped = self.aClass(*args) # ONE (LAST) INSTANCE PER CLASS! return self def __getattr__(self, attrname): print 'Trace:', attrname return getattr(self.wrapped, attrname) """ if __name__ == '__main__': @Tracer class Spam: # like: Spam = Tracer(Spam) def display(self): # Spam is rebound to Wrapper print 'Spam!' * 8 @Tracer class Person: # Person = Tracer(Person) def __init__(self, name, hours, rate): # Wrapper bound to Person self.name = name self.hours = hours self.rate = rate # in-method access not traced def pay(self): return self.hours * self.rate food = Spam() # triggers Wrapper() food.display() # triggers __getitem__ bob = Person('Bob', 40, 50) # bob is really a Wrapper print bob.name # Wrapper embeds a Person print bob.pay() print sue = Person('Sue', 60, 100) print sue.name print sue.pay() print bob.name print bob.pay() """ Trace: display Spam!Spam!Spam!Spam!Spam!Spam!Spam!Spam! Trace: name Bob Trace: pay 2000 Trace: name Sue Trace: pay 6000 Trace: name Bob Trace: pay 2000 """