Hacker News new | past | comments | ask | show | jobs | submit login
Charming Python: Decorators make magic easy (ibm.com)
42 points by mace on Sept 27, 2009 | hide | past | favorite | 5 comments



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)?

   @dec1
   @dec2
   @dec3
   def some_func(arglist):
      ...
vs.

   some_func = dec1(dec2(dec3(fun some_func(arglist) ...)))
I feel like I'm missing something, but perhaps I'm just used to using other idioms for this.


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:

    @login_required
    def profile(...):
        #...
    
    @admin_required
    def ban_user(...):
        #...
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.


> at the point of its definition

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.


Nice!

This makes python quite less boring.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: