I'm inordinately fond of using decorators for adding metadata attributes as markup on functions:
def add_example(*args):
def decorate(fn):
if not hasattr(fn, 'examples'):
fn.examples = []
fn.examples.insert(0, args)
return fn
return decorate
I use decorators like this to add extra command-line options to methods, annotate what types to construct from a command-line string, add typed __doc__ extensions, note example input/output for unit testing and documentation, etc.
I'm genuinely curious, not trying to start flaming, but does this increase the expressiveness of the underlying language? Or is it mainly useful as a syntactic shortcut for function composition (as the article implies)?
Yes, it is syntactic sugar for composition. It exists to make source code more self-documenting because you can see that a function is "decorated" at the point of its definition, rather than some other location where the conceptual context is lost.
The best common use case I can think of for it is web interfaces with access control:
Decorators have also been used for great justice in unit testing frameworks and GUI libraries.
Your example does look a little overzealous, which is why people don't normally use decorators in that way. Usually you'll only see one decorator per function.
Ok, that makes sense, thanks. I guess needing syntax for this is a consequence of Python's quirky lambdas. In languages with full lambdas, you can just wrap an anonymous function at the point of definition.
profile = login_required(function (...) ...) -- in Lua
(define profile (login-required (lambda (...) ...))) ; in Scheme
let profile = login_required(fun ... -> ...) (* in OCaml *)
Putting the decorator on its own line draws attention to it, though. This is probably also another instance of Python's "flat is better than nested" design choice.