A function wrapping a function
A decorator is a function that takes a function and returns a new function. Usually that new function does something extra (logging, timing, caching) and then calls the original.
The @decorator syntax above a def is just shorthand. @timer followed by def do_work(): is exactly the same as writing do_work = timer(do_work) after the definition. Python evaluates the decorator at definition time and replaces the name with whatever it returns.
Once you see decorators that way, the surprise wears off. They are not a special feature, they are an application of the rule that functions are first-class values. You can pass them around and wrap them in other functions, and decorators are the most common reason to do so.