Decorator

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Lad

    Decorator

    I use Python 2.3.
    I have heard about decorators in Python 2.4.
    What is the decorator useful for?
    Thanks for reply
    L.

  • Sybren Stuvel

    #2
    Re: Decorator

    Lad enlightened us with:[color=blue]
    > I use Python 2.3.
    > I have heard about decorators in Python 2.4.
    > What is the decorator useful for?[/color]

    A whole lot of stuff. I've used them for:
    - Logging all calls to a function, including its arguments.
    - Ensuring there is a database connection before the function is
    called.
    - Casting the arguments to certain types before passing them to
    the function.

    And there is much more possible...

    Sybren
    --
    The problem with the world is stupidity. Not saying there should be a
    capital punishment for stupidity, but why don't we just take the
    safety labels off of everything and let the problem solve itself?
    Frank Zappa

    Comment

    • Paul McGuire

      #3
      Re: Decorator

      "Lad" <python@hope.cz > wrote in message
      news:1147416658 .204175.193480@ i39g2000cwa.goo glegroups.com.. .[color=blue]
      > I use Python 2.3.
      > I have heard about decorators in Python 2.4.
      > What is the decorator useful for?
      > Thanks for reply
      > L.
      >[/color]
      Check out these examples on the Python wiki:


      I've gotten to be a big fan of memoize.

      -- Paul


      Comment

      • bruno at modulix

        #4
        Re: Decorator

        Lad wrote:[color=blue]
        > I use Python 2.3.
        > I have heard about decorators in Python 2.4.[/color]

        What Python 2.4 adds is only syntactic sugar for decorators. You can do
        the same - somewhat more explicitely - in 2.3.
        [color=blue]
        > What is the decorator useful for?[/color]

        FWIW, I'm not sure the name 'decorator' is such a great idea. A
        decorator (read 'function decorator') is mainly a callable that takes a
        callable as param and returns another callable, usually wrapping the
        passed callable and adding some responsabilitie s (tracing, logging,
        pre-post condition checks, etc). Two well-known examples are classmethod
        and staticmethod.

        The whole things looks like this:

        def deco(func):
        print "decorating %s" % func.__name__
        def _wrapper(*args, **kw):
        print "%s called " % func.__name__
        res = func(*args, **kw)
        print "%s returned %s" % (func.__name__, str(res))
        return _wrapper

        # python < 2.4
        def somefunc():
        print "in somefunc"
        return 42

        somefunc = deco(somefunc)

        The syntactic sugar added in 2.4 allows you to avoid the explicit call
        to deco():

        # python >= 2.4
        @deco
        def someotherfunc() :
        return "the parrot is dead"


        As you see, apart from the syntactic sugar, there's nothing new here.
        It's just plain old higher order function, well known in any functional
        language.

        HTH
        --
        bruno desthuilliers
        python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
        p in 'onurb@xiludom. gro'.split('@')])"

        Comment

        • Martin Blume

          #5
          Re: Decorator

          "bruno at modulix" schrieb[color=blue]
          >
          > What Python 2.4 adds is only syntactic sugar for decorators.
          > You can do the same - somewhat more explicitely - in 2.3.
          >[color=green]
          > > What is the decorator useful for?[/color]
          >
          >
          > The whole things looks like this:
          >
          > def deco(func):
          > print "decorating %s" % func.__name__
          > def _wrapper(*args, **kw):
          > print "%s called " % func.__name__
          > res = func(*args, **kw)
          > print "%s returned %s" % (func.__name__, str(res))[/color]
          return res
          ^^^^^^^^^^
          Shouldn't here be a return res, so that wrapper
          behaves like the original function?
          [color=blue]
          > return _wrapper
          >
          > # python < 2.4
          > def somefunc():
          > print "in somefunc"
          > return 42
          >
          > somefunc = deco(somefunc)
          >[/color]

          Thanks for the explanation.


          Another question: Isn't decorating / wrapping usually
          done at runtime, so that the @deco notation is pretty
          useless (because you'd have to change the original
          code)?
          What do I miss here?

          Martin


          Comment

          • Sybren Stuvel

            #6
            Re: Decorator

            Martin Blume enlightened us with:[color=blue]
            > Another question: Isn't decorating / wrapping usually done at
            > runtime, so that the @deco notation is pretty useless (because you'd
            > have to change the original code)?[/color]

            Please explain why that would make the @deco notation pretty useless.

            Sybren
            --
            The problem with the world is stupidity. Not saying there should be a
            capital punishment for stupidity, but why don't we just take the
            safety labels off of everything and let the problem solve itself?
            Frank Zappa

            Comment

            • bruno at modulix

              #7
              Re: Decorator

              Martin Blume wrote:[color=blue]
              > "bruno at modulix" schrieb
              >[/color]
              (snip)[color=blue][color=green]
              >>def deco(func):
              >> print "decorating %s" % func.__name__
              >> def _wrapper(*args, **kw):
              >> print "%s called " % func.__name__
              >> res = func(*args, **kw)
              >> print "%s returned %s" % (func.__name__, str(res))[/color]
              >
              > return res
              > ^^^^^^^^^^
              > Shouldn't here be a return res, so that wrapper
              > behaves like the original function?[/color]

              oops, my bad :(
              And yes, of course.
              [color=blue]
              >[color=green]
              >> return _wrapper
              >>
              >># python < 2.4
              >>def somefunc():
              >> print "in somefunc"
              >> return 42
              >>
              >>somefunc = deco(somefunc)
              >>[/color]
              >
              > Thanks for the explanation.
              >
              >
              > Another question: Isn't decorating / wrapping usually
              > done at runtime,[/color]

              It is. I mean, using decorator syntax, this is done during import, which
              happens at runtime.
              [color=blue]
              > so that the @deco notation is pretty
              > useless (because you'd have to change the original
              > code)?[/color]

              I don't understand your question.
              [color=blue]
              > What do I miss here?[/color]

              Ok, I get it (well, I think...).

              The use case for @decorator is for wrapping functions or method *in the
              module/class itself*. It's not for module client code (but this of
              course doesn't prevent client code to dynamically add other wrappers...)

              One of the primary use case makes this pretty clear IHMO : classmethod
              and staticmethod :

              # python < 2.4:
              class Cleese(object):
              def doSillyWalk(cls ):
              pass
              doSillyWalk = classmethod(doS illyWalk)

              # python >= 2.4:
              class Cleese(object):
              @classmethod
              def doSillyWalk(cls ):
              pass

              Another example : CherryPy uses decorators to mark methods which are
              'published' (ie: are action controllers responding to a given URL)


              HTH
              --
              bruno desthuilliers
              python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
              p in 'onurb@xiludom. gro'.split('@')])"

              Comment

              • Martin Blume

                #8
                Re: Decorator

                "Sybren Stuvel" schrieb[color=blue]
                > Martin Blume enlightened us with:[/color]
                Don't know if I enlightened anybody ... :-)
                [color=blue][color=green]
                > > Another question: Isn't decorating / wrapping
                > > usually done at runtime, so that the @deco
                > > notation is pretty useless (because you'd
                > > have to change the original code)?[/color]
                >
                > Please explain why that would make the @deco
                > notation pretty useless.
                >[/color]
                Well, if you're changing the original module, you
                might as well insert the needed functionality in
                the original function, no?
                Or rename the original function, write a function
                having this original name and calling from it the
                original functionality?

                Isn't the point of a decorator to change the
                behavior externally, at runtime, possibly changing
                it in different ways at different places at different
                times?

                So why this @deco notation? Can you apply it externally?
                Meaning to
                import module
                first, then
                @deco(module.fu nc)
                somewhere later?


                Martin



                Comment

                • Martin Blume

                  #9
                  Re: Decorator

                  "bruno at modulix" schrieb[color=blue]
                  >
                  > [snip]
                  >
                  > The use case for @decorator is for wrapping functions
                  > or method *in the module/class itself*.[/color]
                  That was the question. What's the use of doing it
                  like that in the module *itself* (I mean, you change
                  directly the original function)?
                  [color=blue]
                  > It's not for module client code (but this of
                  > course doesn't prevent client code to dynamically
                  > add other wrappers...)
                  >[/color]
                  How do the clients it? The "oldfashion ed"
                  deco(doSillyWal k)
                  way?

                  Martin




                  Comment

                  • bruno at modulix

                    #10
                    Re: Decorator

                    Martin Blume wrote:[color=blue]
                    > "Sybren Stuvel" schrieb
                    >[color=green]
                    >>Martin Blume enlightened us with:[/color]
                    >
                    > Don't know if I enlightened anybody ... :-)[/color]

                    Not sure...

                    But let's hope someone else having doubts about @decorator will find
                    this thread, so we won't have to point him/her to the documentation.
                    [color=blue][color=green][color=darkred]
                    >>>Another question: Isn't decorating / wrapping
                    >>> usually done at runtime, so that the @deco
                    >>>notation is pretty useless (because you'd
                    >>>have to change the original code)?[/color]
                    >>
                    >>Please explain why that would make the @deco
                    >>notation pretty useless.
                    >>[/color]
                    >
                    > Well, if you're changing the original module,[/color]

                    Who's talking about "changing the original module" ?
                    [color=blue]
                    > you
                    > might as well insert the needed functionality in
                    > the original function, no?[/color]

                    higher order functions allow to keep orthogonal responsabilitie s
                    separated.

                    (snip)
                    [color=blue]
                    > Isn't the point of a decorator to change the
                    > behavior externally, at runtime, possibly changing
                    > it in different ways at different places at different
                    > times?[/color]

                    You're confusing the python specific @decorator syntax with the OO
                    design pattern by the same name. This syntax is purely syntactic sugar
                    for a specific use case of higher order functions.
                    [color=blue]
                    > So why this @deco notation?[/color]

                    To improve readability.

                    @decorator
                    def my_one_hundred_ locs_func():
                    ...

                    is much more readable than:
                    def my_one_hundred_ locs_func():
                    ...
                    # 100 LOCS later
                    my_one_hundred_ locs_func = decorator(my_on e_hundred_locs_ func)
                    [color=blue]
                    > Can you apply it externally?[/color]

                    No. It doesn't make sens to replace:
                    mymodule.func = decorator(mymod ule.myfunc)
                    with
                    @decorator
                    mymodule.func

                    Note that all this should be clear for anyone having read the doc...

                    HTH
                    --
                    bruno desthuilliers
                    python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                    p in 'onurb@xiludom. gro'.split('@')])"

                    Comment

                    • Martin Blume

                      #11
                      Re: Decorator

                      "bruno at modulix" schrieb[color=blue][color=green]
                      > >
                      > > Well, if you're changing the original module,[/color]
                      > Who's talking about "changing the original module" ?
                      >[/color]
                      Well, you have to apply @deco in the module where
                      func_to_decorat ed is placed.
                      [color=blue]
                      >[color=green]
                      > > Isn't the point of a decorator to change the
                      > > behavior externally, at runtime, possibly changing
                      > > it in different ways at different places at
                      > > different times?[/color]
                      >
                      > You're confusing the python specific @decorator
                      > syntax with the OO design pattern by the same name.
                      > This syntax is purely syntactic sugar
                      > for a specific use case of higher order functions.
                      >[/color]
                      Yes, that explains my confusion.
                      [color=blue]
                      >[color=green]
                      > > So why this @deco notation?[/color]
                      >
                      > To improve readability.
                      >
                      > @decorator
                      > def my_one_hundred_ locs_func():
                      > ...
                      >
                      > is much more readable than:
                      > def my_one_hundred_ locs_func():
                      > ...
                      > # 100 LOCS later
                      > my_one_hundred_ locs_func = decorator (my_one_hundred _locs_func)
                      >[/color]
                      That makes sense.
                      [color=blue]
                      >
                      > Note that all this should be clear for anyone having
                      > read the doc...
                      >[/color]
                      <blush>
                      Errm, yes, you're so right.

                      Thanks for reading the documentation to me
                      and clearing this up :-)

                      Martin


                      Comment

                      • bruno at modulix

                        #12
                        Re: Decorator

                        Martin Blume wrote:[color=blue]
                        > "bruno at modulix" schrieb
                        >[color=green]
                        >>[snip]
                        >>
                        >>The use case for @decorator is for wrapping functions
                        >>or method *in the module/class itself*.[/color]
                        >
                        > That was the question. What's the use of doing it
                        > like that in the module *itself*[/color]
                        Readability.

                        Since the decoration (in the module) is somehow part of the function
                        definition, it's more obvious to have it expressed with a modifier-like
                        syntax at the top of the def statement than expressed as a function call
                        and rebinding after the end of def block. When reading the code, with
                        the @decorator syntax, the use of the decorator is pretty evident.

                        Once again, this is nothing more than syntactic sugar - but syntactic
                        sugar counts. FWIW, function decorators seems to be *much* more used
                        since the introduction of the @decorator syntax, when you could do the
                        same thing since the introduction of nested scopes and closures in
                        Python (dont remember the version, but this is not really new).
                        [color=blue]
                        > (I mean, you change
                        > directly the original function)?[/color]

                        If you mean that the code added by the decorator could be injected
                        directly in the function, that's not always true (ie: classmethod and
                        staticmethod for example), and it just plain sucks anyway - you don't
                        write a decorator for a single function, you write it to separate
                        orthogonal concerns, like tracing, handling auth, partial application of
                        function, etc...
                        [color=blue][color=green]
                        >>It's not for module client code (but this of
                        >>course doesn't prevent client code to dynamically
                        >>add other wrappers...)
                        >>[/color]
                        >
                        > How do the clients it?[/color]

                        Like it did since there are nested scopes and closures in Python. Higher
                        order functions are not really something new, you know - Lisp had them
                        way back in 1958 !-)
                        [color=blue]
                        > The "oldfashion ed"
                        > deco(doSillyWal k)
                        > way?[/color]

                        from monty.python import Cleese
                        Cleese.doSillyW alk = deco(Cleese.doS illyWalk)

                        HTH
                        --
                        bruno desthuilliers
                        python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
                        p in 'onurb@xiludom. gro'.split('@')])"

                        Comment

                        • Martin Blume

                          #13
                          Re: Decorator

                          "bruno at modulix" schrieb[color=blue]
                          >
                          > [lucid introduction into decorators]
                          >[/color]
                          Thanks for the help in understanding decorators.

                          Martin


                          Comment

                          • Michele Simionato

                            #14
                            Re: Decorator

                            I will shamelessly plug in my own decorator module:
                            http://www.phyast.pitt.edu/~micheles.../decorator.zip and


                            Comment

                            Working...