call to eggs while useful for decorating functionsthis coding scheme still has issues when applied to methods-- shortcoming we'll address in later revision enclosing scopes and globals closure functions--with enclosing def scope references and nested defs--can often achieve the same effectespecially for static data like the decorated original function in this examplethoughwe would also need counter in the enclosing scope that changes on each calland that' not possible in python (recall from that the nonlocal statement is -onlyin xwe can still use either classes and attributes per the prior sectionor other options moving state variables out to the global scope with declarations is one candidateand works in both and xcalls def tracer(func)state via enclosing scope and global def wrapper(*args**kwargs)instead of class attributes global calls calls is globalnot per-function calls + print('call % to % (callsfunc __name__)return func(*args**kwargsreturn wrapper @tracer def spam(abc)print( csame asspam tracer(spam@tracer def eggs(xy)print( *ysame aseggs tracer(eggsspam( spam( = = = really calls wrapperassigned to spam wrapper calls spam eggs( eggs( = really calls wrapperassigned to eggs global calls is not per-decoration hereunfortunatelymoving the counter out to the common global scope to allow it to be changed like this also means that it will be shared by every wrapped function unlike class instance attributesglobal counters are cross-programnot per-function--the counter is incremented for any traced function call you can tell the difference if you compare this version' output with the prior version' --the singleshared global call counter is incorrectly updated by calls to every decorated functionc:\codepython decorator py call to spam call to spam decorators