In Python, a:b:c is syntactic sugar. When used inside square brackets [a:b:c], the CPython parser translates it into a call to the built-in slice() function.
# These are evaluated identically by CPython:
my_list[1:10:2]
my_list[slice(1, 10, 2)]At the C level, a slice object is a simple struct (PySliceObject) containing three PyObject pointers: start, stop, and step.
One of the trickier parts of slicing is dealing with missing bounds and negative indices (e.g., [-5:]). Calculating the actual start and stop integers for an array of a specific length is non-trivial.
To solve this, CPython exposes an indices(length) method on slice objects.
s = slice(-3, None, None)
print(s.indices(10)) # Output: (7, 10, 1)The indices() method takes the length of the target sequence and calculates the exact, positive integer coordinates (start, stop, step) needed to execute the slice. It handles negative indices, out-of-bounds indices, and missing steps.
When you write a custom sequence in Python, your __getitem__ is bound to the C-level sq_item or mp_subscript slots.
In Python 3, CPython routes most bracket lookups through mp_subscript (the mapping protocol).
- User writes
v[1:4]. - CPython parser builds a
slice(1, 4, None)object. - CPython looks up the
__getitem__method on your class. - It passes the
sliceobject as theindexparameter. - It is entirely up to the Python-level
__getitem__method to inspect the type ofindexusingisinstance(index, slice)and react appropriately.