bytes#

bytes is the operator’s wire-format type. Immutable sequence of integers in [0, 255]. Same method surface as str for the methods that make sense at the byte level. Always specify encoding when crossing the boundary to str.

Encode a str to bytes.

"café".encode("utf-8")           # b'caf\xc3\xa9'

Decode bytes to str.

b"caf\xc3\xa9".decode("utf-8")   # "café"

Build from a hex string; round-trip back to hex.

header = bytes.fromhex("4d5a9000")   # MZ header start
header.hex()                          # '4d5a9000'

Common encodings.

Encoding

When

utf-8

The default. Variable-width; ASCII-compatible.

ascii

Strict 7-bit; raises on non-ASCII. Use for protocols that are pure ASCII (HTTP headers, SMTP).

latin-1

1:1 byte mapping. Useful for round-tripping arbitrary bytes through str without loss.

utf-16

Windows wide strings; surrogate pairs.

bytearray#

bytearray is the mutable sibling. Same interface, with in-place mutation via slice assignment and append / extend.

buf = bytearray(b"HTTP/1.1 ")
buf.extend(b"200 OK\r\n")
buf[0:4] = b"http"            # in-place
bytes(buf)                    # freeze a snapshot

memoryview#

memoryview is the zero-copy slice over a bytes / bytearray / array.array / numpy array. Read or write without copying the backing buffer.

Build a view over a buffer; slicing produces another view, not a copy.

buf = bytearray(b"payload-bytes")
mv  = memoryview(buf)
mv[0:7]                      # <memory at ...>

Materialise a view as bytes when the consumer wants a copy.

bytes(mv[0:7])               # b'payload'

Slice-assign through the view to mutate the backing buffer in place.

mv[8:13] = b"chunk"

Use memoryview when feeding large buffers to a syscall or a parser that accepts the buffer protocol; the alternative buf[a:b] copies.

Method catalog#

The complete instance-method surface on bytes. Most are mirrors of the str methods that make sense on byte sequences. bytearray adds the in-place mutators below.

Common#

Method

Effect

decode(encoding='utf-8', errors='strict')

Decode to str.

hex(sep='', bytes_per_sep=1)

Hex-encoded string.

bytes.fromhex(s)

Parse a hex string (classmethod).

count(sub[, start[, end]])

Non-overlapping occurrence count.

find(sub[, start[, end]])

Lowest index of sub or -1.

rfind(sub[, start[, end]])

Highest index or -1.

index(sub[, start[, end]])

Like find but raises on miss.

rindex(sub[, start[, end]])

Like rfind but raises.

startswith(prefix[, start[, end]])

Prefix test.

endswith(suffix[, start[, end]])

Suffix test.

replace(old, new[, count])

Replace occurrences.

translate(table[, delete])

Per-byte substitution via a bytes.maketrans table.

bytes.maketrans(from, to)

Build a translation table (staticmethod).

Split, join, trim, case#

Method

Effect

split(sep=None, maxsplit=-1)

Split on sep.

rsplit(sep=None, maxsplit=-1)

Split from the right.

splitlines(keepends=False)

Split on newline sequences.

partition(sep)

Split into (head, sep, tail).

rpartition(sep)

Split at the last sep.

join(iterable)

Concatenate iterable with this sequence between.

strip([chars])

Trim from both ends.

lstrip([chars])

Trim leading.

rstrip([chars])

Trim trailing.

removeprefix(p)

Strip prefix if present (3.9+).

removesuffix(s)

Strip suffix if present (3.9+).

ljust(width, fill=b' ')

Left-justify to width.

rjust(width, fill=b' ')

Right-justify to width.

center(width, fill=b' ')

Centre to width.

zfill(width)

Left-pad with 0 to width.

lower()

Lowercase ASCII characters.

upper()

Uppercase ASCII characters.

title()

Title-case ASCII words.

swapcase()

Swap ASCII case.

capitalize()

Capitalise the first byte.

expandtabs(tabsize=8)

Replace tabs with spaces.

Predicates#

Method

True when

isalpha()

All bytes are ASCII letters.

isdigit()

All bytes are ASCII digits.

isalnum()

All bytes are ASCII alphanumeric.

isspace()

All bytes are ASCII whitespace.

isascii()

Every byte is < 128 (always True for bytes).

islower()

Cased bytes are lowercase.

isupper()

Cased bytes are uppercase.

istitle()

Title-cased.

bytearray-only#

In addition to every method above, bytearray supports in-place mutation.

Method

Effect

append(b)

Append a single byte.

extend(iterable)

Append every byte from an iterable.

insert(i, b)

Insert at index.

pop([i])

Remove and return a byte.

remove(b)

Remove the first occurrence by value.

clear()

Drop every byte.

reverse()

Reverse in place.

A few method examples.

hex and bytes.fromhex round-trip a hex string.

b"\xde\xad\xbe\xef".hex()
'deadbeef'
bytes.fromhex("deadbeef")
b'\xde\xad\xbe\xef'

find returns the first index of a sub-sequence or -1.

b"the quick fox".find(b"quick")
4

replace returns a new bytes with the replacement applied; bytes is immutable so the original is unchanged.

b"GET / HTTP/1.0".replace(b"HTTP/1.0", b"HTTP/1.1")
b'GET / HTTP/1.1'

bytearray.extend mutates the buffer in place.

buf = bytearray(b"HTTP/1.1 ")
buf.extend(b"200 OK\r\n")
bytes(buf)
b'HTTP/1.1 200 OK\r\n'

Operator overloading#

bytes and bytearray share most of the sequence-protocol dunders.

Operator

Dunder

Returns

a + b

__add__

Concatenation.

a * n

__mul__

Repetition.

a == b

__eq__

Equality.

a < b

__lt__

Lexicographic less than.

hash(a)

__hash__

Hash (bytes only; bytearray is unhashable).

a in b

__contains__

Sub-sequence test (or single-byte membership).

a[i] / a[i:j]

__getitem__

Index returns an int; slice returns a bytes / bytearray.

a[i:j] = c

__setitem__

In-place slice assignment (bytearray only).

len(a)

__len__

Length.

iter(a)

__iter__

Byte-by-byte iteration (yields int).

bool(a)

__bool__

False only for the empty sequence.

A wire-frame class can use __bytes__ so bytes(frame) serialises to the wire form.

class Frame:
    def __init__(self, op, payload): self.op, self.payload = op, payload
    def __bytes__(self):
        return bytes([self.op, len(self.payload)]) + self.payload

bytes(Frame(0x10, b"hello"))
b'\x10\x05hello'

A sub-sequence test reads naturally with in; behind the scenes Python calls __contains__.

b"deadbeef" in b"the deadbeef header"
True

References#