Python 2.5’s “partition” saves my bacon

So I was on more than one IRC channel today asking a question that I got lots of answers to, all of which looked really messy to me, so I dug into the documentation and found that in Python 2.5, strings have a new method, called “partition”.

Here’s the trouble I had, and why “partition” helps:

>>> m = "parent:child"
>>> x = m.split(":")[1]
>>> x
'child'

This is actually pretty close to what I want. I want to split m, and assign the second element in the resulting list to x. The problem arises when there is no “:”. In that case, that second line is actually trying to assign to x by referencing an index that is beyond the end of the list. You get an “index out of range” error.

So you’re left with a number of options. You can use an “if” to check for the existence of the colon.

if ":" in m:
x = m.split(":")[1]

I guess. But then I have to use another “if” to check and see if x was ever defined, or I have to initialize x ahead of time. At this point I’m onto at least three lines of code for something that takes 1 line in Ruby, Perl, or PHP. That just *can’t* be right!

You can also go ahead and just add the “:” explicitly to “m”:

>>> y = m + ":"
>>> y
'parent:'
>>> x = m.split(":")[1]
>>> x
''

Nothing wrong with that except I still think I just shouldn’t have to do that. I should be able to, as a last resort, go with regex and do a one-liner that assigns everything after “:” to x, and if there isn’t a “:”, then x would wind up being empty. Something along the lines of x = re.search(“:.*”, m) – or something like that.

Well, partition solves the problem rather nicely. From the documentation:

Split the string at the first occurrence of sep, and return a 3-tuple containing the part before the separator, the separator itself, and the part after the separator. If the separator is not found, return a 3-tuple containing the string itself, followed by two empty strings. New in version 2.5.

Here’s what I did with it:

>>> y
'parent:'
>>> x = y.partition(":")[2]
>>> x
''

Of course, I got an empty string in this case, but “partition” did what I wanted “split” to do – namely, assign ” or None to “x” if the separator didn’t exist. I guess what makes this possible with “partition” is the fact that it returns a fixed-length tuple no matter what, while split returns an arbitrary-length list, which would introduce ambiguities in cases where multiple splits are done to a string.