Skip to main content

Objects/bytearrayobject.c

Source:

cpython 3.14 @ ab2d84fe1023/Objects/bytearrayobject.c

bytearray is the mutable counterpart to bytes. It supports in-place modification and the buffer protocol for zero-copy I/O.

Map

LinesSymbolRole
1-200bytearray_new, bytearray_initConstruction from int (zeroed), bytes, str+encoding, iterable
201-400bytearray_resizeInternal resize (may reallocate buffer)
401-600bytearray_getitem, bytearray_setitemIndex/slice get and in-place set
601-800bytearray_concat, bytearray_repeat+ and * operators
801-1200bytearray_find, bytearray_count, bytearray_indexSubstring search
1201-1600bytearray_replace, bytearray_split, bytearray_joinMutation and splitting
1601-1800bytearray_decodebytearray.decode(encoding)
1801-2000bytearray_extend, bytearray_append, bytearray_insertList-like mutation
2001-2400Buffer protocolbf_getbuffer, bf_releasebuffer
2401-2800bytearray_hex, bytearray_fromhexHex conversion

Reading

Construction

// CPython: Objects/bytearrayobject.c:55 bytearray_init
static int
bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds)
{
if (count == 0) {
/* bytearray() or bytearray(0) → empty */
return 0;
}
if (PyLong_CheckExact(arg)) {
/* bytearray(n) → n zero bytes */
count = PyLong_AsSsize_t(arg);
if (PyByteArray_Resize((PyObject *)self, count) < 0) return -1;
memset(PyByteArray_AS_STRING(self), 0, count);
} else if (PyBytes_Check(arg)) {
/* bytearray(b'...') → copy */
...
} else {
/* bytearray(iterable of ints) */
...
}
}

bytearray(n) produces n null bytes. bytearray(b'hello') copies. bytearray([72, 101, 108]) iterates.

Resize

// CPython: Objects/bytearrayobject.c:240 PyByteArray_Resize
int
PyByteArray_Resize(PyObject *self, Py_ssize_t size)
{
/* Over-allocate with growth factor to amortize append cost */
Py_ssize_t alloc = _Py_SIZE_ROUND_UP(size, 8);
if (alloc != ob->ob_alloc) {
char *sval = (char *)PyMem_Realloc(ob->ob_start, alloc + 1);
...
}
ob->ob_val = ob->ob_start;
ob->ob_bytes = size;
ob->ob_val[size] = '\0'; /* always null-terminated */
}

bytearray is always null-terminated internally (like bytes) even though it is mutable.

In-place setitem

// CPython: Objects/bytearrayobject.c:430 bytearray_ass_subscript
static int
bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *values)
{
if (PyIndex_Check(index)) {
/* Single byte assignment */
Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError);
int ival = PyLong_AsLong(values);
if (ival < 0 || ival > 255) {
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
return -1;
}
self->ob_start[i] = (char)ival;
} else {
/* Slice assignment — may change length */
...
}
}

append / extend

// CPython: Objects/bytearrayobject.c:1820 bytearray_append
static PyObject *
bytearray_append(PyByteArrayObject *self, PyObject *arg)
{
int value = PyLong_AsLong(arg);
if (value < 0 || value > 255) {
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
return NULL;
}
if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self) + 1) < 0) return NULL;
PyByteArray_AS_STRING(self)[Py_SIZE(self) - 1] = value;
Py_RETURN_NONE;
}

Buffer protocol

// CPython: Objects/bytearrayobject.c:2060 bytearray_getbuffer
static int
bytearray_getbuffer(PyByteArrayObject *obj, Py_buffer *view, int flags)
{
/* Expose the internal buffer directly — zero-copy */
return PyBuffer_FillInfo(view, (PyObject *)obj,
PyByteArray_AS_STRING(obj),
Py_SIZE(obj), 0 /* writable */, flags);
}

bytearray satisfies the writable buffer protocol. Passing one to socket.recv_into() avoids a copy.

hex / fromhex

// CPython: Objects/bytearrayobject.c:2450 bytearray_hex_impl
static PyObject *
bytearray_hex_impl(PyByteArrayObject *self, int sep, int bytes_per_sep)
{
/* same logic as bytes.hex() */
return _Py_strhex_with_sep(PyByteArray_AS_STRING(self),
PyByteArray_GET_SIZE(self), sep, bytes_per_sep);
}

bytearray(b'\xde\xad').hex('-', 1) gives 'de-ad'.

gopy notes

bytearray is in objects/bytearray.go. The mutable buffer is a Go []byte with separate alloc tracking for over-allocation. append, extend, insert, pop, remove are implemented as Go slice operations. The buffer protocol exposes the slice directly via objects.BufferFill. decode delegates to codecs.Decode.