def decodecorate(aclass)for attrattrval in aclass __dict__ items()if type(attrvalis functiontypesetattr(aclassattrdecorator(attrval)return aclass return decodecorate @decorateall(tracerclass persondef __init__(selfnamepay)self name name self pay pay def giveraise(selfpercent)self pay *( percentdef lastname(self)return self name split()[- not __dict__ use class decorator applies func decorator to methods person decorateall)(personperson decodecorate(personbob person('bob smith' sue person('sue jones' print(bob namesue namesue giveraise print(' fsue payprint(bob lastname()sue lastname()when this code is run as it isthe class decorator applies the tracer function decorator to every method and produces trace message on calls (the output is the same as that of the preceding metaclass version of this example) :\codepy - decoall-deco-any py call to __init__ call to __init__ bob smith sue jones call to giveraise call to lastname call to lastname smith jones notice that the class decorator returns the originalaugmented classnot wrapper layer for it (as is common when wrapping instance objects insteadas for the metaclass versionwe retain the type of the original class--an instance of person is an instance of personnot of some wrapper class in factthis class decorator deals with class creation onlyinstance creation calls are not intercepted at all this distinction can matter in programs that require type testing for instances to yield the original classnot wrapper when augmenting class instead of an instanceclass decorators can retain the original class type the class' methods are not their original functions because they are rebound to decoratorsbut this is likely less important in practiceand it' true in the metaclass alternative as well also note thatlike the metaclass versionthis structure cannot support function decorator arguments that differ per method in the decorated classbut it can handle such exampleapplying decorators to methods