bytes.endswith()

The mirror of startswith. Most useful for terminators and trailers — checking a message ended cleanly, or that a file carries its expected footer.

Bytes methodPython 3.0+Live demo
Common call
data.endswith(b'\r\n')
Returns
bool — True or False, never an error
Replaces
data[-len(suffix):] == suffix, which allocates and breaks on empty
Watch out
a LIST of suffixes is a TypeError; it must be a tuple
bytes.endswith(suffix[, start[, end]])
→ bool

Demo

Live evaluation
Try:
Inputs
sstrdata (encoded as utf-8)
suffixstrsuffix to test
Output
bytes('abcdef', 'utf-8').endswith(bytes('def', 'utf-8'))
True

A suffix test, byte for byte, returning True or False. The same two edge cases as startswith apply: an empty suffix is always True, and a suffix longer than the data is False rather than an error. Because it compares in place it is both faster and safer than negative slicing, which misbehaves when the suffix is empty.

Parameters

NameTypeRequiredDescription
suffixbytes | tupleyesBytes to test for, or a TUPLE of alternatives. A list raises TypeError.
startintno (0)Byte offset to treat as the beginning of the region tested.
endintno (len)Byte offset to treat as the END — the suffix is matched here, not at the real end.

Return value

bool — True if the buffer ends with suffix. A tuple of suffixes returns True if ANY of them match.

Common patterns

Check a message terminator
Confirms a protocol frame arrived complete.
if buffer.endswith(b'\r\n'):
    dispatch(buffer)
Match several extensions
The tuple form replaces a chain of or clauses.
if path_bytes.endswith((b'.jpg', b'.jpeg', b'.png')):
    handle_image()
Verify a trailing signature
Some formats put their marker at the end rather than the start.
if data.endswith(ZIP_EOCD_MAGIC):
    ...

Examples

1. Matches
b'abcdef'.endswith(b'def')
Returns
True
2. Does not match
b'abcdef'.endswith(b'xyz')
Returns
False
3. Empty is always True
b'abc'.endswith(b'')
Returns
True
4. Too long
b'ab'.endswith(b'abc')
Returns
False
5. Tuple of options
b'a.png'.endswith((b'.jpg', b'.png'))
Returns
True
6. end shifts the target
b'abcdef'.endswith(b'cd', 0, 4)
Returns
True

Pitfalls

1. Negative slicing breaks on an empty suffix
The reason to prefer this method. data[-0:] is the WHOLE buffer, not an empty slice, so the hand-rolled comparison gives False where endswith correctly gives True.
Slicing misfires
s = b''
b'abc'[-len(s):] == s
False # -0 slices everything
Use the method
b'abc'.endswith(b'')
True
2. A list of suffixes is a TypeError
Only a tuple is accepted, exactly as with startswith. Alternatives built dynamically usually arrive as a list and need converting.
List rejected
b'abc'.endswith([b'c'])
TypeError: endswith first arg must be bytes or a tuple of bytes, not list
Convert to tuple
b'abc'.endswith(tuple(suffixes))
True
3. end moves where the suffix is matched
Unlike most methods, end does not merely bound a search — it redefines where the buffer is considered to finish, so the suffix is matched at that point.
Not the real end
b'abcdef'.endswith(b'ef', 0, 4)
False # buffer treated as abcd
Match the new end
b'abcdef'.endswith(b'cd', 0, 4)
True
4. The suffix must be bytes
A str raises rather than returning False. Checking a filename in bytes form against a str extension is the usual way this appears.
str rejected
b'a.png'.endswith('.png')
TypeError: endswith first arg must be bytes or a tuple of bytes, not str
Bytes literal
b'a.png'.endswith(b'.png')
True

When to use

Use it
  • Confirming a message or frame terminator
  • Matching one of several file extensions with the tuple form
  • Verifying a trailing signature or footer
Reach for something else
  • The match could be anywhere → rfind or the in operator
  • The data is text → decode first and use str.endswith
  • Removing the suffix → removesuffix does the test and the trim together

Notes

Complexity
O(len(suffix)) — stops at the first differing byte
Return
A bool; never raises for a non-matching suffix
CPython impl
Objects/bytesobject.c :: bytes_endswith
Memory
No allocation — unlike negative slicing, which copies
Thread-safe
Yes — bytes are immutable

FAQ

Because data[-len(suffix):] breaks when the suffix is empty: -0 is 0, so the slice is the entire buffer and the comparison fails. endswith handles that correctly and avoids the allocation too.

b'abc'.endswith(b'')   # True
b'abc'[-0:] == b''     # False

History

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