Learning decorators is usually one of the first 'a-hah!' moments in the experience of someone coming to python from another language. The wonders of the yield statement often follow. Here's the obligatory link to 'A Curious Course on Coroutines and Concurrency' which is an excellent introduction to one of Python's most unknown yet useful features. As he puts it, they are similar to 'lightweight classes' that you can use to encapsulate state and send messages to. In the video, he starts with generators, and eventually ends up with an entire operating system (scheduler, syscalls, etc...) based on coroutines.
Decorators take a function and return a new function. 9 times out of 10 they're used as an easy way to create wrappers: do something and then execute the original function, or execute the original function and then process it before handing it off.
They're doubly useful in Python because Python has only limited support for functions as blocks.
Even as an experience Python developer, I love finding explanations like this. Sometimes you forget about obscure aspects of a particular feature once you get in a groove and reading things like this usually makes me think back and go "Ohh, shoot, if I would've remembered that, I would have built X this way..." or something similar. This goes for about anything I feel like I "know".
[EDIT]: Basically, whatever function is returned from the decorator line (the function itself, if there is no call, or the results from a function call otherwise) is applied to the decorated function.
As a recent convert to Python, I have to say that decorators is one of the most useful features I have come across thusfar, both syntacticly and logically.