File: class/Workbook/Exercises/Lab13/ex2.txt
# This solution also tests a "tracer" function decorator; # modify as shown to test your "timer" decorator instead; # Metaclass factory: apply any decorator to all methods of a class from types import FunctionType from mytools import tracer, timer def decorateAll(decorator): class MetaDecorate(type): def __new__(meta, classname, supers, classdict): for attr, attrval in classdict.items(): if type(attrval) is FunctionType: classdict[attr] = decorator(attrval) return type.__new__(meta, classname, supers, classdict) return MetaDecorate class Person(metaclass=decorateAll(tracer)): # Apply a decorator to all def __init__(self, name, pay): self.name = name self.pay = pay def giveRaise(self, percent): self.pay *= (1.0 + percent) def lastName(self): return self.name.split()[-1] bob = Person('Bob Smith', 50000) sue = Person('Sue Jones', 100000) print(bob.name, sue.name) sue.giveRaise(.10) print(sue.pay) print(bob.lastName(), sue.lastName()) class Person(metaclass=decorateAll(tracer)): # Apply tracer class Person(metaclass=decorateAll(timer())): # Apply timer, defaults class Person(metaclass=decorateAll(timer(label='**'))): # Decorator arguments # If using timer: total time per method print('-'*40) print('%.5f' % Person.__init__.alltime) print('%.5f' % Person.giveRaise.alltime) print('%.5f' % Person.lastName.alltime) # Class decorator factory: apply any decorator to all methods of a class from types import FunctionType from mytools import tracer, timer def decorateAll(decorator): def DecoDecorate(aClass): for attr, attrval in aClass.__dict__.items(): if type(attrval) is FunctionType: setattr(aClass, attr, decorator(attrval)) # Not __dict__ return aClass return DecoDecorate @decorateAll(tracer) # Use a class decorator class Person: # Applies func decorator to methods def __init__(self, name, pay): # Person = decorateAll(..)(Person) self.name = name # Person = DecoDecorate(Person) self.pay = pay def giveRaise(self, percent): self.pay *= (1.0 + percent) def lastName(self): return self.name.split()[-1] bob = Person('Bob Smith', 50000) sue = Person('Sue Jones', 100000) print(bob.name, sue.name) sue.giveRaise(.10) print(sue.pay) print(bob.lastName(), sue.lastName()) @decorateAll(tracer) # Decorate all with tracer @decorateAll(timer()) # Decorate all with timer, defaults @decorateAll(timer(label='@@')) # Same but pass a decorator argument # If using timer: total time per method print('-'*40) print('%.5f' % Person.__init__.alltime) print('%.5f' % Person.giveRaise.alltime) print('%.5f' % Person.lastName.alltime)