Today, I ran across a Hacker News thread where someone mentioned that they often ask job applicants to whiteboard a function
that would return a row of Pascal's Triangle.
I couldn't resist, so and came up with this:
Obviously, I was less interested in returning the row as I was in building the triangle itself and printing it. Returning the actual row is left as an exercise to the reader.
A while back, I was hanging out on some Python forum and someone posted a comment about not being able to wrap their head around decorators. I spent some time on what I thought was a helpful comment, and that was that. Recently I figured it'd be worthwhile to expand that comment a bit. So, here we go.
First, it helpes to understand that python variables are not boxes in which you store values, but rather name tags that you hang onto objects. Please don't move on until you grok this, it's the central principle to decorators.
Second, in Python, functions are objects. Function names themselves are just name tags hung onto their respective function objects.
Finally, here's a simple definition of a decorator: It's just a function. Seriously. Nothing magic about it all. It takes another function as an argument (the function being decorated). It returns yet another function object.
If that sounded like I just said, "Function function function function function," (which is how I felt when trying to wrap my head around decorators), here's a small python program that may help out:
If we'd run this code in the interactive interpreter, here's the output we'd get:
That above syntax is what made decorators click for me. All we've done here is taken the orig_function nametag, and hung it onto the third_function object (remember, my_decorator returns third_func). So when we call orig_function() now, what we're really calling is third_func().
I used the above syntax ( a=decorator(b) ) until I was sure I understood how decorators worked before I switched to using the shorter @ syntax.
is equivalent to
which isn't as intuitive and is probably the main roadblock to understanding decorators right at first, but nicer to use once you've got the hang of things.
In this example, we didn't do anything in the my_decorator function with the argument that was passed in ( orig_function ), but we could have called it and returned something other than third_func, depending on what orig_function returned. Remember, a decorator is just a function, you can do anything inside a decorator you'd do in a vanilla Python function. It just needs to take a function as a parameter, and return another function.