Skip to main content

Objects/bytearrayobject.c (part 3)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/bytearrayobject.c

This annotation covers mutation methods and the buffer protocol. See objects_bytearrayobject_detail for bytearray.__new__, __getitem__, __setitem__, and objects_bytearrayobject2_detail for append, decode, replace, split.

Map

LinesSymbolRole
1-80bytearray.extendAppend all bytes from an iterable
81-180bytearray.insertInsert a single byte at an index
181-280bytearray.removeRemove first occurrence of a byte value
281-380bytearray.popRemove and return the byte at an index
381-480bytearray.reverseReverse in place
481-700Buffer protocol (bf_getbuffer)Export a writable Py_buffer for zero-copy I/O
701-800bytearray.copy / bytearray.clearShallow copy and truncate

Reading

bytearray.extend

// CPython: Objects/bytearrayobject.c:820 bytearray_extend
static PyObject *
bytearray_extend(PyByteArrayObject *self, PyObject *iterable_of_ints)
{
/* Fast path for bytes/bytearray */
if (PyBytes_CheckExact(iterable_of_ints)) {
return bytearray_iconcat(self, iterable_of_ints);
}
if (PyByteArray_CheckExact(iterable_of_ints)) {
return bytearray_iconcat(self, iterable_of_ints);
}
/* General: iterate and append each int */
PyObject *it = PyObject_GetIter(iterable_of_ints);
while ((item = PyIter_Next(it)) != NULL) {
int val = PyNumber_AsSsize_t(item, PyExc_ValueError);
if (val < 0 || val > 255) {
PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
...
}
bytearray_append_byte(self, (unsigned char)val);
}
...
}

bytearray.insert

// CPython: Objects/bytearrayobject.c:900 bytearray_insert
static PyObject *
bytearray_insert(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs)
{
int item;
Py_ssize_t where;
/* Clamp where to valid range */
if (where < 0) where += Py_SIZE(self);
if (where < 0) where = 0;
if (where > Py_SIZE(self)) where = Py_SIZE(self);
/* Resize and shift */
if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self) + 1) < 0) return NULL;
memmove(self->ob_bytes + where + 1, self->ob_bytes + where,
Py_SIZE(self) - where - 1);
self->ob_bytes[where] = item;
Py_RETURN_NONE;
}

bytearray.insert(i, v) shifts elements right by one position using memmove, then writes the new byte. Same complexity and semantics as list.insert.

Buffer protocol

// CPython: Objects/bytearrayobject.c:1480 bytearray_getbuffer
static int
bytearray_getbuffer(PyByteArrayObject *obj, Py_buffer *view, int flags)
{
/* Export a writable buffer view over the bytearray storage.
While exported, the bytearray cannot be resized. */
if (obj->ob_exports > 0 && (flags & PyBUF_WRITABLE)) {
/* Allow multiple writable exports only if no resize has occurred */
}
return PyBuffer_FillInfo(view, (PyObject *)obj,
obj->ob_bytes, Py_SIZE(obj),
0, /* not readonly */
flags);
}

bytearray implements the buffer protocol so that code like socket.recv_into(ba) or struct.pack_into(fmt, ba, 0, ...) can write directly into its storage without copying. While a buffer view is exported, resizing raises BufferError.

bytearray.reverse

// CPython: Objects/bytearrayobject.c:1050 bytearray_reverse
static PyObject *
bytearray_reverse(PyByteArrayObject *self)
{
Py_ssize_t n = Py_SIZE(self);
unsigned char *lo = self->ob_bytes;
unsigned char *hi = lo + n - 1;
while (lo < hi) {
unsigned char tmp = *lo;
*lo++ = *hi;
*hi-- = tmp;
}
Py_RETURN_NONE;
}

In-place reversal using two-pointer swap. O(n) time, O(1) extra space.

gopy notes

bytearray.extend is objects.ByteArrayExtend in objects/bytearray.go. bytearray.insert is objects.ByteArrayInsert. The buffer protocol is implemented via objects.ByteArray.GetBuffer which returns a objects.Buffer struct with a pointer to the underlying []byte. Resize prevention while exported is tracked with an exports counter.