the next section explains first look at user-defined function decorators although python provides handful of built-in functions that can be used as decoratorswe can also write custom decorators of our own because of their wide utilitywe're going to devote an entire to coding decorators in the final part of this book as quick examplethoughlet' look at simple user-defined decorator at work recall from that the __call__ operator overloading method implements function-call interface for class instances the following code uses this to define call proxy class that saves the decorated function in the instance and catches calls to the original name because this is classit also has state information-- counter of calls madeclass tracerdef __init__(selffunc)remember originalinit counter self calls self func func def __call__(self*args)on later callsadd logicrun original self calls + print('call % to % (self callsself func __name__)return self func(*args@tracer def spam(abc)return same as spam tracer(spamwrap spam in decorator object print(spam( )print(spam(' '' '' ')really calls the tracer wrapper object invokes __call__ in class because the spam function is run through the tracer decoratorwhen the original spam name is called it actually triggers the __call__ method in the class this method counts and logs the calland then dispatches it to the original wrapped function note how the *name argument syntax is used to pack and unpack the passed-in argumentsbecause of thisthis decorator can be used to wrap any function with any number of positional arguments the net effectagainis to add layer of logic to the original spam function here is the script' and output--the first line comes from the tracer classand the second gives the return value of the spam function itselfc:\codepython tracer py call to spam call to spam abc trace through this example' code for more insight as it isthis decorator works for any function that takes positional argumentsbut it does not handle keyword argudecorators and metaclassespart