bytes.center()

Centring with an odd byte to spare is where the surprise lives: sometimes the extra goes left, sometimes right, and the rule is not "always left".

Bytes methodPython 3.0+Live demo
Common call
data.center(20, b'-')
Returns
a new bytes object at least width long
Replaces
computing left and right padding by hand
Watch out
the fill must be exactly ONE byte; the odd-padding side is not intuitive
bytes.center(width[, fillbyte])
→ bytes

Demo

Live evaluation
Try:
Inputs
sstrdata (encoded as utf-8)
widthinttotal width
fillstrfill byte (one char)
Output
bytes('ab', 'utf-8').center(6, bytes('*', 'utf-8'))
b'**ab**'

When the padding splits evenly the result is symmetric. Compare the two odd cases carefully: ab centred to 7 gets the extra star on the LEFT, but abc centred to 6 gets it on the RIGHT. CPython puts the extra byte on the left only when the data length and the width have different parity — it is not a fixed side. Data already at or beyond the width comes back unchanged, and a fill that is not exactly one byte raises TypeError.

Parameters

NameTypeRequiredDescription
widthintyesMinimum total length. Shorter widths return the data unchanged.
fillbytebytesno (b' ')A bytes object of length exactly 1. Longer or shorter raises TypeError.

Return value

bytes — A new bytes object padded on both sides to at least width. Never truncates. When the padding cannot be split evenly, which side gets the extra byte depends on a parity rule.

Common patterns

Centre a heading in a fixed-width report
Legacy line-printer style output.
line = title.center(80, b'=')
Build a banner
A fill byte other than space makes a visual rule.
banner = b' ' + label + b' '
banner = banner.center(40, b'-')
Centre real text
Decode first so width is counted in characters, not bytes.
text.decode('utf-8').center(20).encode('utf-8')

Examples

1. Even padding
b'ab'.center(6, b'*')
Returns
b'**ab**'
2. Odd, extra left
b'ab'.center(7, b'*')
Returns
b'***ab**'
3. Odd, extra right
b'abc'.center(6, b'*')
Returns
b'*abc**'
4. Default space
b'ab'.center(4)
Returns
b' ab '
5. Already wide
b'abcdef'.center(3)
Returns
b'abcdef'
6. Bad fill
b'ab'.center(6, b'**')
Returns
TypeError: center() argument 2 must be a byte string of length 1, not bytes

Pitfalls

1. The odd byte does not always go to the same side
CPython's rule is that the extra padding goes left when len and width differ in parity, right when they match. Code that assumes "always left" or "always right" produces off-by-one alignment on half its inputs.
Inconsistent
b'ab'.center(7, b'*'), b'abc'.center(6, b'*')
(b'***ab**', b'*abc**')
Pad explicitly
pad = width - len(d)
b'*' * (pad // 2) + d + b'*' * (pad - pad // 2)
your rule, stated
2. The fill must be exactly one byte
A multi-byte fill is a TypeError, which means a non-ASCII fill character encoded as UTF-8 is rejected — it is two or more bytes.
Two bytes
b'ab'.center(6, '·'.encode())
TypeError: center() argument 2 must be a byte string of length 1
ASCII fill
b'ab'.center(6, b'.')
b'..ab..'
3. Width counts bytes, not characters
Centring encoded text to a character width goes wrong as soon as a multi-byte character appears, because the buffer is longer than the text looks.
Off by bytes
'é'.encode().center(5, b'*')
b'**\xc3\xa9*' # 2 bytes, not 1 char
Centre text
'é'.center(5, '*').encode()
centred by character

When to use

Use it
  • Fixed-width ASCII report and banner output
  • Aligning a label inside a byte-based line
Reach for something else
  • Text with non-ASCII characters → decode, centre, encode
  • You need a predictable odd-padding side → pad manually
  • A non-ASCII fill character — it must be one byte

Notes

Complexity
O(width) — one allocation and fill
Return
A new bytes object; the original when already wide enough
CPython impl
Objects/bytesobject.c :: stringlib_center
Memory
Allocates a buffer of max(len, width)
Thread-safe
Yes — bytes are immutable

FAQ

CPython computes the left padding as half the total plus an adjustment based on the parity of both the width and the data length. When the two parities differ, the extra byte goes left; when they match, it goes right. It is deliberate but not obvious, and str.center follows the same rule.

b'ab'.center(7, b'*')   # b'***ab**'
b'abc'.center(6, b'*')  # b'*abc**'

History

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