curiouslythe decorator function in this example can almost be coded as class instead of functionwith the proper operator overloading protocol the following slightly simplified alternative works similarly because its __init__ is triggered when the decorator is applied to the classand its __call__ is triggered when subject class instance is created our objects are really instances of tracer this timeand we essentially just trade an enclosing scope reference for an instance attribute hereclass tracerdef __init__(selfaclass)on @decorator self aclass aclass use instance attribute def __call__(self*args)on instance creation self wrapped self aclass(*argsone (lastinstance per classreturn self def __getattr__(selfattrname)print('traceattrnamereturn getattr(self wrappedattrname@tracer class spamdef display(self)print('spam! food spam(food display(triggers __init__ likespam tracer(spamtriggers __call__ triggers __getattr__ as we saw in the abstract earlierthoughthis class-only alternative handles multiple classes as beforebut it won' quite work for multiple instances of given classeach instance construction call triggers __call__which overwrites the prior instance the net effect is that tracer saves just one instance--the last one created experiment with this yourself to see howbut here' an example of the problem@tracer class persondef __init__(selfname)self name name bob person('bob'print(bob namesue person('sue'print(sue nameprint(bob nameperson tracer(personwrapper bound to person bob is really wrapper wrapper embeds person sue overwrites bob oopsnow bob' name is 'sue'this code' output follows--because this tracer only has single shared instancethe second overwrites the firsttracename bob tracename sue tracename sue decorators