In Python 2, itertools.imap will be faster since it doesn't realize a list. Also, if you are memory constrained, xrange doesn't realize a list either, whereas range does (but the article notes that range was slightly faster than xrange in his tests--I don't know if that's still true in Python 2, the article is 9 years old).
In Python 3, the map builtin is basically equivalent what itertools.imap was in Python 2, so it is the best choice. (Also, the range builtin in Python 3 no longer realizes a list.)
I tried it with n=1000 and n=10000, and found that using xrange made it slightly faster, as did using itertools.imap, but the difference was pretty small.
(Here I'm using the stock Python 2.7.1 on a 2011 MacBook Pro.)
That's what I would expect, since xrange works like a generator; but the internals of its implementation in CPython back when the article ran its original tests were evidently less efficient than they are now.
the difference was pretty small
I suspect that's because the strings being concatenated are really small (the largest will only be 5 bytes for n=10000). I would expect the difference to get bigger as the individual strings get larger.
In Python 3, the map builtin is basically equivalent what itertools.imap was in Python 2, so it is the best choice. (Also, the range builtin in Python 3 no longer realizes a list.)