4

I use Python's str.partition in my code in three ways:

before, __, after = string.partition(sep)
before = string.partition(sep)[0]
after = string.partition(sep)[2]

While I use str.partition frequently, I've always wondered why it returns the separator. The first line surely would benefit from it not returning the separator, and in my opinion, also the third line would become more intuitive.

While I acknowledge that one can re-build the string with

"".join(string.partition(sep))

I do not see any use case for this.

So, what is the rationale of the inclusion of the separator in the returned tuple?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Torsten Bronger
  • 9,899
  • 7
  • 34
  • 41

2 Answers2

6

Following jonrsharpe's lead, I found this mail from Raymond Hettinger. It explains the rationale and shows many use cases. The middle value can be used as a boolean flag, and they were even close to calling it "found" instead of "sep". And in almost all of his many examples where the middle value isn't ignored, it's indeed used as a boolean flag (and sometimes also used further). The "old pattern" had been to call find, check < 0 or >= 0, and then conditionally extract the parts. The new partition function replaced that pattern well. A typical example:

Old:

i = p.find('=')
if i >= 0:
    name = p[:i]
    value = p[i+1:]
    (use name and value)

New:

name, found, value = p.partition('=')
if found:
    (use name and value)
Stefan Pochmann
  • 27,593
  • 8
  • 44
  • 107
4

Per the documentation, str.partition and the associated str.rpartition were:

New in version 2.5.

Looking at the what's new for that version provides some rationale for these methods, which "simplify a common use case":

The find(S)() method is often used to get an index which is then used to slice the string and obtain the pieces that are before and after the separator. partition(sep)() condenses this pattern into a single method call that returns a 3-tuple containing the substring before the separator, the separator itself, and the substring after the separator.


Looking at some of the examples originally provided when the function was developed, e.g. replacing:

i = host.find(':')
if i >= 0:
    port = host[i+1:]
    ...

with:

_, sep, port = host.partition(':')
if sep:
    ...

including sep in the output makes it easy to check whether it was found in the string. There are various examples that use only two of the three returned values, but which they don't need varies!

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Your second cited paragraph rather suggests that the new pattern should return only "before" and "after" rather than also the separator. – Torsten Bronger May 24 '15 at 12:30
  • @TorstenBronger that's as good as I could get from the published documentation, there's no PEP for this; if you want to dive into the mailing list to see if you can find Raymond Hettinger's original suggestion and any related follow-up, be my guest! – jonrsharpe May 24 '15 at 12:31
  • @TorstenBronger see e.g. http://marc.info/?t=112529477700001 for discussion around this – jonrsharpe May 24 '15 at 12:39
  • 1
    In http://marc.info/?l=python-dev&m=112529473001162 Hettinger mentions something that I consider a use case: That you want to distinguish between "no separator found" and "separator was very last character". In other words, you want to do `sep in string` and `string.partition` in one step. (FWIW, I need `sep in string` very rarely, and then, I check it explicitly.) I would accept an answer mentioning this. – Torsten Bronger May 24 '15 at 13:05
  • @TorstenBronger I've updated my answer with an example from that discussion – jonrsharpe May 24 '15 at 14:03