A timing decorator is applied to 40 pricing functions. Afterwards the generated API documentation is empty, pickling one of the functions fails, and a test that dispatches on the function name breaks. Explain the single cause, the fix, and three things the fix still does not restore.

A timing decorator is applied to 40 pricing functions. Afterwards the generated API documentation is empty, pickling one of the functions fails, and a test that dispatches on the function name breaks. Explain the single cause, the fix, and three things the fix still does not restore.

Approach: Ask what object the caller holds after decoration, and which attributes of the original the wrapper failed to carry over.

The decorator returned a wrapper function, which carries its own name, docstring, module, qualified name and annotations, so every consumer of that metadata sees the wrapper instead of the original, and applying functools.wraps to the wrapper copies those attributes across and records a reference to the original, which repairs the documentation, the pickling and the name dispatch. Pickle stores a function by module and qualified name and looks it up again on load, so a wrapper whose qualified name does not resolve back to itself fails. What wraps does not restore is the parameter signature seen by code doing introspection when the wrapper takes packed arguments, the identity of the original for anything comparing function objects, and the shape of the traceback, which keeps the extra frame, along with the call overhead of about 100 nanoseconds. The original stays reachable through the wrapped attribute that wraps sets.

Follow-up: How would you write the decorator so a library that reads the signature sees the exact parameters of the original?

Key concepts: decorator, functools.wraps, qualified name, introspection.