bytes.translate()

One pass, many substitutions. Where chained replace calls each copy the whole buffer, translate rewrites every byte exactly once.

Bytes methodPython 3.0+Live demo
Common call
data.translate(bytes.maketrans(frm, to))
Returns
a new bytes object of the same length, unless delete is used
Replaces
a chain of replace calls for single-byte swaps
Watch out
it only maps SINGLE bytes — it cannot swap multi-byte sequences
bytes.translate(tabletable — A 256-byte table, normally from bytes.maketrans. Pass None to only delete.type: bytes | None · required, /, deletedelete — Bytes to remove entirely. Applied as well as the table mapping.type: bytes · default: b''=b'')
→ bytes

Demo

Live evaluation
Try:
Inputs
sstrdata (encoded as utf-8)
frmstrbytes to map from
tostrbytes to map to
Output
bytes('hello', 'utf-8').translate(bytes.maketrans(bytes('el', 'utf-8'), bytes('ip', 'utf-8')))
b'hippo'

maketrans pairs up the two arguments byte by byte — the first byte of frm maps to the first byte of to, and so on — and translate then rewrites the data through that table. Bytes not mentioned pass through untouched, as the partial case shows. The mapping is strictly one byte to one byte, so the two arguments must be the same length; the last case shows the ValueError you get otherwise.

Parameters

NameTypeRequiredDescription
tablebytes | NoneyesA 256-byte table, normally from bytes.maketrans. Pass None to only delete.
deletebytesno (b'')Bytes to remove entirely. Applied as well as the table mapping.

Return value

bytes — A new bytes object with every byte mapped through the table. Bytes listed in delete are removed entirely.

Common patterns

Swap several bytes at once
One pass instead of a chain of replace calls.
table = bytes.maketrans(b'abc', b'xyz')
out = data.translate(table)
Delete bytes without mapping
Pass None as the table when you only want removal.
clean = data.translate(None, b'\r\x00')
Build a simple byte cipher
A fixed permutation table is a substitution cipher.
rot = bytes.maketrans(plain_alphabet, shifted_alphabet)

Examples

1. hello to hippo
b'hello'.translate(bytes.maketrans(b'el', b'ip'))
Returns
b'hippo'
2. Map three
b'abcabc'.translate(bytes.maketrans(b'abc', b'xyz'))
Returns
b'xyzxyz'
3. Delete only
b'abc'.translate(None, b'b')
Returns
b'ac'
4. Map and delete
b'abc'.translate(bytes.maketrans(b'abc', b'xyz'), b'c')
Returns
b'xy'
5. Length mismatch
bytes.maketrans(b'ab', b'x')
Returns
ValueError: maketrans arguments must have same length
6. Short table
b'abc'.translate(b'short')
Returns
ValueError: translation table must be 256 characters long

Pitfalls

1. Single bytes only
translate maps byte to byte. It cannot turn one byte into two, or replace a multi-byte sequence — reaching for it to swap words or CRLF pairs will not work.
Cannot map pairs
data.translate(bytes.maketrans(b'\r\n', b'\n'))
ValueError: arguments must have same length
Use replace
data.replace(b'\r\n', b'\n')
handles sequences
2. The table must be exactly 256 bytes
Passing anything shorter raises. Always build it with maketrans rather than by hand, which is what the length rule is really telling you.
Hand-made table
b'abc'.translate(b'short')
ValueError: translation table must be 256 characters long
Use maketrans
b'abc'.translate(bytes.maketrans(b'a', b'x'))
b'xbc'
3. Multi-byte characters get mangled
On UTF-8 encoded text, translate rewrites individual bytes with no idea they belong to one character. Mapping a byte inside a multi-byte sequence produces invalid UTF-8 that fails on decode.
Breaks the encoding
'héllo'.encode().translate(bytes.maketrans(b'\xc3', b'\x41'))
invalid utf-8
Work on text
'héllo'.translate(str.maketrans('é', 'e'))
'hello'
4. It returns a new object
Bytes are immutable, so the result must be assigned. Calling translate and discarding the return value does nothing at all.
Result dropped
data.translate(table)
data
unchanged
Assign it
data = data.translate(table)
updated

When to use

Use it
  • Swapping several single bytes in one pass
  • Stripping a set of unwanted byte values
  • Fixed substitution ciphers and byte-level normalisation
  • Hot paths where chained replace calls cost too much
Reach for something else
  • Multi-byte sequences → replace
  • UTF-8 encoded text → decode and use str.translate
  • Pattern-based edits → the re module, which works on bytes

Notes

Complexity
O(n) — one table lookup per byte, regardless of how many mappings
Return
A new bytes object; the same length unless delete removed something
CPython impl
Objects/bytesobject.c :: bytes_translate
Memory
Allocates the result plus a 256-byte table
Thread-safe
Yes — bytes are immutable

FAQ

Each replace copies the entire buffer, so five substitutions mean five full passes. translate does them all in one pass through a lookup table — the win grows with both the buffer size and the number of mappings.

data.translate(bytes.maketrans(b"abc", b"xyz"))

History

3.0
bytes.translate arrived with the bytes type in the text/binary split.
3.6
The delete argument became keyword-friendly and the table accepts None.