What Code Golf Taught Me About Python
So I’ve become seriously addicted to code golf. For those that don’t know, code golf is a competition where you try to pass some programming test with a program consisting of the least number of characters. I chose to play code golf in Python because I wanted to learn more about the language. I’ll probably eventually do the same for Ruby.
I know the title of this might be controversial. There’s alot of people who have never tried it, know no one who has, but still have strong opinions on why golfing is a negative practice to undertake. These people are wrong. Golfing is just a programming puzzle. It doesn’t remove your ability to recognize ugly code. Anyone who tries to “golf” outside of a golfing context has bigger problems.
What follows is a brief guide to the idioms that I learned through code golf that could be useful in real programming. It will also serve as a helpful set of tips for python golfers. I’ll probably do a followup post with idioms that are useful but are completely worthless for any real programming.
I am by no means a code golf expert. I recently attained the 6th rank and have 5th well within striking distance, but my average per “hole” isn’t staggering. So please keep in mind this is by no means a definitive list of techniques required to be successful. If anyone wants to email me some tips on the Dancing Queens puzzle, feel free. I’ve been beating my head against a wall on this one for a few weeks and haven’t even gotten close to Mark Byer’s 100. I don’t know Mark, but I’d like to shake his hand.
White Space
Most people (wrongly) believe that white space is the reason Python is a poor language for golfing. In very few cases do the white space rules result in longer python programs. (The real reason that Python gets soundly beat by Ruby or Perl is a combination of the verbose nature of the standard python library and the strictness with types that requires additional keystrokes to overcome.) Back to our war on white space…
- You can almost always turn single if/while/for loops into one-liners
- Nested control structures that require white space aren’t used as often as you think
- exec can save the day (not useful for real programming!)
The second point will be covered by some of the techniques below so let’s deal with the first.
if a: # before bob() jim() if a: bob();jim() # after
Simple. Effective. One line if/while/for statements shouldn’t be used in regular python very often but there are times when removing that white space can sometimes substantially clean up the code.
Functional Programming
Hopefully this is obvious but code golfers should be ready and willing to map() all kinds of things all over the place. Fall in love with map(). You generally won’t use reduce() in golf because most often, after mapping, you’ll tend to use either join() or sum() or something along those lines. Lambdas also get a fair bit of action in code golf. You’ll become much more familiar with this section of the language.
Conditional Moves
Often times your if statements are nothing but glorified conditional move instructions. Those if statements can almost always be replaced by simpler statements:
if a<0: # beginner python b=2*a else: b=3*a b=2*a if a<0 else 3*a # proper python b=a<0 and 2*a or 3*a # codegolf1 b=a*(3,2)[a<0] # codegolf2
Now, all of the above idioms have pros and cons as far both function and readability. Let’s get the caveats out of the way. The first code golf technique above only works if your first expression doesn’t evaluate to 0. The second code golf expression doesn’t short circuit (so, for example, (0,a/b)[b!=0] does not prevent division by 0).
All three of these idioms (if/else, and/or, and the index into a tuple) are worth understanding and recognizing. They can all be very powerful in certain real world situations.
Operators
Code golfers become intimately familiar with the order of operations (removing those parentheses!). This is extremely useful information to know by heart, but you shouldn’t be dropping those parentheses in your real code. As a special note, the two string operators, * and %, are crucial. Most people are hopefully aware of these already. ‘%’ is the string formatting operator. As a code golfer, you will master it and all its variants. Similarly, strings can be multiplied by integers to repeat them. If you want a hint of how powerful these can could potentially be for a code golfer, think about multiplying and string formatting mixed with the exec command.
Booleans as Values
Here is where alot of the magic begins to happen. When all else fails, Python will treat a Boolean True as an integer value 1, and a False as 0. This becomes extremely powerful when mixed with some of the techniques above.
print "Good Morning!" + (mailcount>0)*" You have new mail!" print "You have %d email message%s."%(mailcount, 's'*(mailcount != 1))
Miscellaneous
Here’s a grab bag of other useful things. Hopefully this is self-explanatory.
a=b=0 # I had no idea python let you do this transpose=zip(*list) rev = anything[::-1] # reversed() that works on any sequence print `x`+`y` # convert to string (via repr) print x, # ends print with a space (instead of a newline)
September 29th, 2008 at 9:52 am
I’m pretty sure you meant:
b=a<0 and 2*a or 3*a
not:
b=2*a and a<0 or 3*a
September 29th, 2008 at 11:23 am
Yes, indeed, Michael. I’ve fixed it above. Thanks
September 29th, 2008 at 12:27 pm
b=a*(3,2)[a>> 2*(2,3)
(2, 3, 2, 3)
September 29th, 2008 at 12:29 pm
My comment was eaten! Here’s what I mean to say:
http://dpaste.com/81231/
September 29th, 2008 at 12:45 pm
Steve,
It is correct. Your dpaste doesn’t have the square brackets required to do the indexing. Indexing into a tuple is one of the highest precedence operations and happens before the multiplication.
If you paste: a*(3,2)[a<0]
.. into python after setting ‘a’ it will work correctly. Depending on the value of ‘a’ (whether positive or negative) it will multiply ‘a’ by either 3 or 2.
September 29th, 2008 at 1:24 pm
Error in the “grab bag” part — [::-1] only works on sequences, not any iterable:
>>> anything = (_ for _ in [1, 2, 3, 4, 5])
>>> anything[::-1]
Traceback (most recent call last):
File “”, line 1, in
TypeError: ‘generator’ object is unsubscriptable
September 29th, 2008 at 1:41 pm
Fixed! Absolutely correct. My python vocabulary failed me.
You guys are good.
September 29th, 2008 at 2:13 pm
Save one character: b=a*(3-(a<0))
September 30th, 2008 at 3:26 am
My favorite thing I learned was that you could do this:
print”foo”
*without* a space. Which I would never use outside of code golf and actually bothers me a bit that it works. But I like knowing it
September 30th, 2008 at 7:06 am
@Ben,
There are actually alot of times when you can remove spaces that just seem plain wrong. The same trick works with parentheses as well.
Another example is with numeric literals:
1or 2
… is valid python, as well.
I have a list of similar things that make great tricks in python but that you’d never ever use in real coding.
September 30th, 2008 at 9:30 am
Thanks for the cool tutorial. The one caveat I have for us beginner python programmers is the following:
a=b=0 # I had no idea python let you do this
This is great for values, but not objects like lists (unless you want them to be the same object). I.e.,
a = b = [1,2,3]
a[1] = 5
Because a and b are now the same object, b[1] also equals 5.
October 6th, 2008 at 5:37 pm
Hi Louis,
I also have been playing codegolf. You might have seen. I think you are really a great competitor. Much faster solving a problem efficiently than me. I have started thinking how to solve dancing queens and conways game. Not easy.
/Hendrik
October 8th, 2008 at 10:19 am
Hey hendrik,
Definitely seen your name on the charts. I’ve been taking a break for a few weeks now consumed with other hobbies. The dancing queens is still in the back of my mind since it’s one of the simplest of my unsolved problems (that and Hanoi).
December 10th, 2008 at 9:00 pm
There are actually alot of times when you can remove spaces that just seem plain wrong. The same trick works with parentheses as well.
Another example is with numeric literals:
1or 2
… is valid python, as well.
I have a list of similar things that make great tricks in python but that you’d never ever use in real coding.
March 23rd, 2009 at 6:59 am
lbrandy.com » Blog Archive » Some tips for getting started on Project Euler says:[...] casually mentioned that he had messed around with Project Euler. He knew I was a bit of a geek for online programming fun and games. Project Euler is a very large set of programming puzzles (247, to date) that tests your ability to [...]