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:
print"\n"print"Printing Pascal's triangle."num_rows=input("How many rows do you want: ")deftriangle(num_rows):width=2*num_rows-1prev_row=[]triangle=[]forrow_numinrange(num_rows):row_width=row_num+1# the number of items that will appear in this row
ifrow_num==0:row=[1]else:row=[]foriinrange(row_width):ifi==0ori==row_width-1:# the '1's on either end of each row
row.append(1)else:# Calculate the sum of the two numbers above this position
row.append(prev_row[i-1]+prev_row[i])prev_row=rowtriangle.append(row)returntriangle# Actually generate the triangle
triangle=triangle(num_rows)# Now print it out nicely
# First, get the width of the last row in the triangle (printed as a string)
width=len(" ".join(["%s"%numfornumintriangle[-1]]))forlineintriangle:printstr.center(" ".join(["%s"%numfornuminline]),width)
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 needed to force an SSL connection for only a subdirectory of a website. Apache's mod_rewrite came to my rescue.
RewriteEngine On
RewriteCond %{HTTPS} off # the following rules only apply if the connection isn't already HTTPS
# Next line captures any bits after the directory we're interested in
# and stuff it into %1, which gets expanded back out in the rule at the end
RewriteCond %{REQUEST_URI} /dir-that-needs-ssl/(.*)
RewriteRule / https://www.example.com/dir-that-needs-ssl/%1 [R,L]
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:
deforig_function():print"Hello!"defmy_decorator(function_to_decorate):# Decorator takes a function as an argument
defthird_func():# Yes, it's totally legit to create nested function definitions.
# It's a very common decorator idiom.
print"Take Off, eh?"returnthird_func# return a function object. Note: we don't have parens here.
If we'd run this code in the interactive interpreter, here's the output we'd get:
>>>orig_function()Hello!>>># now, we're going to decorate orig_function with my_decorator
>>>orig_function=my_decorator(orig_function)>>>orig_function()"Take off, eh?"
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.
orig_function=my_decorator(orig_function)
is equivalent to
@my_decoratordeforig_function():print"Hello!"
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.