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
"""