bytes.rpartition()

partition from the other end. The absent-separator rule is mirrored too: partition fills the HEAD, rpartition fills the TAIL. Getting that backwards is the whole failure mode.

Bytes methodPython 3.0+Live demo
Common call
stem, dot, ext = name.rpartition(b'.')
Returns
a 3-tuple, always — split at the last separator
Replaces
rfind plus two slices plus a -1 check
Watch out
absent separator → (b'', b'', data): everything in the TAIL
bytes.rpartition(sepsep — Separator to split on, at its last occurrence. An empty separator raises ValueError.type: bytes · required)
→ tuple

Demo

Live evaluation
Try:
Inputs
sstrdata (encoded as utf-8)
sepstrseparator
Output
bytes('a=b=c', 'utf-8').rpartition(bytes('=', 'utf-8'))
(b'a=b', b'=', b'c')

The split happens at the LAST occurrence, so a=b=c gives a=b as the head and c as the tail — the opposite grouping from partition. The extension case is the classic use: file.tar.gz splits into file.tar and gz. Study the absent case closely, because it is mirrored from partition: with no separator, rpartition puts the whole input in the TAIL, giving two empty parts first.

Parameters

NameTypeRequiredDescription
sepbytesyesSeparator to split on, at its last occurrence. An empty separator raises ValueError.

Return value

tuple — Always (head, separator, tail), split at the LAST occurrence. When the separator is absent, the tail holds everything and the other two are empty — the mirror of partition.

Common patterns

Split a file extension
The last dot is the extension boundary.
stem, _, ext = name.rpartition(b'.')
Split a path into directory and leaf
The last slash separates them.
directory, _, leaf = path.rpartition(b'/')
Separate host and port
The last colon, which survives IPv6 addresses.
host, _, port = addr.rpartition(b':')

Examples

1. Last separator
b'a=b=c'.rpartition(b'=')
Returns
(b'a=b', b'=', b'c')
2. Extension
b'file.tar.gz'.rpartition(b'.')
Returns
(b'file.tar', b'.', b'gz')
3. Absent fills tail
b'abc'.rpartition(b'=')
Returns
(b'', b'', b'abc')
4. partition differs
b'abc'.partition(b'=')
Returns
(b'abc', b'', b'')
5. At the end
b'abc='.rpartition(b'=')
Returns
(b'abc', b'=', b'')
6. Unpack is safe
h, s, t = b'x'.rpartition(b'=')
Returns
always works

Pitfalls

1. A missing separator fills the TAIL, not the head
The mirror of partition, and easy to get backwards. Code that reads the head as "the value" gets empty bytes when the separator is absent — partition would have given the whole input there.
Empty head
b'noext'.rpartition(b'.')[0]
b''
Test the separator
h, s, t = name.rpartition(b'.')
stem = h if s else t
handles both
2. Only the LAST occurrence splits
Earlier separators stay in the head. Right for extensions and paths; wrong when you wanted the first split.
Earlier kept
b'a=b=c'.rpartition(b'=')
(b'a=b', b'=', b'c')
partition for first
b'a=b=c'.partition(b'=')
(b'a', b'=', b'b=c')
3. An empty separator raises
No meaningful split point exists, so Python refuses rather than guessing.
No split point
b'abc'.rpartition(b'')
ValueError: empty separator
Guard it
parts = d.rpartition(sep) if sep else (b'', b'', d)
explicit

When to use

Use it
  • File extensions, path leaves and host:port — anything keyed on the LAST separator
  • Key-value parsing where the value may itself contain the separator
  • Anywhere rfind plus slicing would need a -1 check
Reach for something else
  • The FIRST separator → partition
  • Every field → split or rsplit
  • Real paths → os.path or pathlib handle edge cases

Notes

Complexity
O(n) worst case; scans from the right and stops at the first match
Return
A new three-item tuple of new bytes objects
CPython impl
Objects/bytesobject.c :: bytes_rpartition
Memory
Allocates the tuple and up to three parts
Thread-safe
Yes — bytes are immutable

FAQ

So that the tail always means "everything after the last separator". With no separator there is nothing before it, so the whole input is "after". It also makes name.rpartition(b".")[2] a safe way to take the extension-or-whole-name in one expression.

b'abc'.rpartition(b'=')
# (b'', b'', b'abc')

History

3.0
bytes.rpartition arrived with the bytes type in the text/binary split.