the last example of the prior section raises an important issue function decorators have variety of options for retaining state information provided at decoration timefor use during the actual function call they generally need to support multiple decorated objects and multiple callsbut there are number of ways to implement these goalsinstance attributesglobal variablesnonlocal closure variablesand function attributes can all be used for retaining state class instance attributes for examplehere is an augmented version of the prior examplewhich adds support for keyword arguments with *syntaxand returns the wrapped function' result to support more use cases (for nonlinear readerswe first studied keyword arguments in and for readers working with the book examples packagesome filenames in this are again implied by the command-lines that follow their listings)class tracerstate via instance attributes def __init__(selffunc)on decorator self calls save func for later call self func func def __call__(self*args**kwargs)on call to original function self calls + print('call % to % (self callsself func __name__)return self func(*args**kwargs@tracer def spam(abc)print( csame asspam tracer(spamtriggers tracer __init__ @tracer def eggs(xy)print( *ysame aseggs tracer(eggswraps eggs in tracer object spam( spam( = = = really calls tracer instanceruns tracer __call__ spam is an instance attribute eggs( eggs( = really calls tracer instanceself func is eggs self calls is per-decoration here like the originalthis uses class instance attributes to save state explicitly both the wrapped function and the calls counter are per-instance information--each decoration gets its own copy when run as script under either or xthe output of this version is as followsnotice how the spam and eggs functions each have their own calls counterbecause each decoration creates new class instancec:\codepython decorator py call to spam call to spam call to eggs coding function decorators