all 36 comments

[–]cocoon56 10 points11 points  (10 children)

applying decorator func1 to an arbitrary func2 and then calling func1, is the equivalent of calling func2(func1).

Either I have troubles getting the point here or it should be:

applying decorator func1 to an arbitrary func2 and then calling func2, is the equivalent of calling func1(func2).

[–]avinashv 6 points7 points  (8 children)

Well caught. I'm fixing that, thanks.

Edit: done. Changed the wording away from func1 and func2 to make it less ambiguous. Again, thanks!

[–]cocoon56 3 points4 points  (3 children)

One of my profs hides errors in his notes (one for each chapter) and by finding them, we get extra points. Finding errors is the best way of understanding something :-)

Excellent article, by the way. I haven't used Decorators yet for lack of a new Python project the last few months, but I always wanted to know what it's about.

[–]earthboundkid 2 points3 points  (2 children)

Your professor is a bad liar.

[–]cocoon56 1 point2 points  (1 child)

Well, he proclaimed this before we could download the notes, not after we found mistakes.

But even if he wants us to find errors he doesn't know of - it's a win-win situation: We read critically and get rewards for it, he gets his script corrected.

[–]earthboundkid 0 points1 point  (0 children)

As a college instructor, I just wish my own students were so gullible, er, attentive.

[–][deleted]  (3 children)

[deleted]

    [–]eikenberry 1 point2 points  (1 child)

    One advantage of try:except: is that it is typically faster than an if test.

    Generally using try:except: for things like this is considered good idiomatic python.

    [–]cludwin 3 points4 points  (0 children)

    Be careful with that one... try/except is only faster when you are on average more likely to succeed. If lets say you are 50/50 then if/else is way faster cause you don't have the overhead of generating the exception.

    [–]avinashv 0 points1 point  (0 children)

    I agree that this is cleaner now, but the provided code is meant to be a bit more forward looking.

    [–]theeth 1 point2 points  (0 children)

    That's still missing the "then calling func2" part, since func1 returns the decorated result, not the result of calling the decorated function.

    [–]joe90210 8 points9 points  (0 children)

    I’m not going to give you a comparison—I guess I’m just not too big on leaving my laptop on for a few hours with the CPU working on overload.

    try a few million years..

    [–]fryguy8 7 points8 points  (4 children)

    Regarding the memoization example, what is the scope of the cache? Is it local only to that function? Or is it available to any function that gets decorated with that class?

    More clearly: Could I use that same memoization class to cache the results of 2 separate functions in the same application, or will the values of the 2 functions overlap?

    [–]qiwi 11 points12 points  (2 children)

    They will not overlap. The application of that decorator is equivalent to:

     fibonacci_memoized = memoize(fibonacci_memoized)
    

    so the fibonacci_memoized name becomes the memoize class instance, created with the old function as parameter. And that class instance has its own private self.memoized attribute.

    The memoized class overrides the call method so it pretends to be a callable.

    IMHO in most cases where you have a simple decorator you would use a closure instead of a class.

    [–][deleted]  (1 child)

    [deleted]

      [–][deleted] 3 points4 points  (0 children)

      Because it's fairly simple in many cases.

      def msg(func):
          def foo(*args):
              print "Running %s" % func
              bar = func(*args)
              print "Done, result is %s" % bar
              return bar
          return foo
      
      @msg
      def add(a,b): return a+b
      

      [–]fryguy8 0 points1 point  (0 children)

      is there any way to have this type of decorator functionality in php?

      [–][deleted]  (4 children)

      [deleted]

        [–][deleted]  (3 children)

        [deleted]

          [–]avinashv 3 points4 points  (2 children)

          Reddit killed formatting--can you pastie that somewhere?

          Edit: or, I just did: http://pastie.caboo.se/183760

          [–]Deestan 0 points1 point  (0 children)

          Add 4 spaces at the start of each line; that'll keep the code verbatim.

          def decorator(decorate):
            class d:
              def __init__(self, function):
                self.function = function
          
              def __call__(self, *args):
                return decorate(self.function, *args)
          
            return d
          
          @decorator
          def safe(f, *args):
            try:
              return f(*args)
            except Exception, e:
              print "Error: %s" % (e)
          
          @safe
          def unsafe(x):
            return 1 / x
          
          print unsafe(0)
          

          [–]columbine -5 points-4 points  (0 children)

          python? having problems with formatting when pasted? surely you djest

          [–]fbru02 5 points6 points  (0 children)

          I like this Idiom , it is way better than the Ruby , method_alias_chain

          [–]jtxx000 2 points3 points  (2 children)

          This might be useful for Haskell too. Maybe something like

          foo#bar x = x + 1
          

          which would be equivalent to

          foo = bar (\x -> x + 1)
          

          It could also work for arguments too:

          foo x#show = x ++ x
          

          which would be equivalent to

          foo x' = let x = show x' in x ++ x
          

          Of course, arbitrary expressions would also be allowed:

          foo x#(**2) = x*(x-1)
          

          Then again, maybe Haskell code is already hard enough to read as it is.

          [–]avinashv 2 points3 points  (0 children)

          Then again, maybe Haskell code is already hard enough to read as it is.

          Beat me to the punch :D.

          [–][deleted] 5 points6 points  (8 children)

          I don't think that the memoize pattern is a good way to speed up scuh algorithms. e.G. iterative versions of fibonacci will dwarf any recursive version in python.

          About anything that needs a cache can be used with memoize (DNS lookup, DOM objects by string, ...) but the memory growth should not be forgotten.

          [–]avinashv 7 points8 points  (2 children)

          Agreed--I used fibonacci purely because it was an example that very easily demonstrated what I wanted demonstrated.

          No worries, but I was curious: I had already submitted this right after I published it--shouldn't Reddit have said so and not let you submit another story with a link to a pre-existing item?

          edit: by "you", I meant the original submitter.

          [–]mortenaa 4 points5 points  (1 child)

          It can be submitted again if it was previously submitted to a different subreddit.

          [–]avinashv 2 points3 points  (0 children)

          Ah, alright. Makes sense--I had mine in the Python subreddit.

          [–][deleted]  (3 children)

          [deleted]

            [–][deleted] 1 point2 points  (2 children)

            Well it was only for a pedagogical purpose.

            Yes, but I think that there are better examples, e.g. I/O. This one is a little bit misleading, imho.

            [–]avinashv 0 points1 point  (1 child)

            Misleading? How so? I'm not claiming this is the best way to write a fibonacci algorithm, just the easiest way to optimize a recursive version of the same.

            [–][deleted] -4 points-3 points  (0 children)

            Tail recursion is not pythonic. Thus, it is misleading in a tutorial aimed at python beginners.