slice(start, stop, None) vs slice(start, stop, 1)

Question:

I was surprised to read here that

The start and step arguments default to None

since it also says:

slice(start, stop, step=1)

Return a slice object representing the set of indices specified by range(start, stop, step).

So I expected the default argument value for the step parameter to be 1.

I know that slice(a, b, None) == slice(a, b, 1) returns False, but I am curious if slice(a, b, None) always returns the same slice as slice(a, b, 1), or if there is some example that I haven’t been able to think of for which they will return different slices.

I couldn’t find anything about this in the extensive post on slicing here

Asked By: Joe

||

Answers:

Slice’s step indeed defaults to None, but using step 1 and None should be equivalent for all practical purposes. That’s because in the C code where the step is actually used, there are checks which transform None into 1 anyway:

int
PySlice_GetIndices(PyObject *_r, Py_ssize_t length,
                   Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
{
    PySliceObject *r = (PySliceObject*)_r;
    if (r->step == Py_None) {
        *step = 1;
    } ...    
}

And:

int
PySlice_Unpack(PyObject *_r,
               Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
{
    PySliceObject *r = (PySliceObject*)_r;
    ...
    if (r->step == Py_None) {
        *step = 1;
    }
    ...
}

If you’re wondering why they don’t just default to 1 instead, perhaps it’s because users may still want to slice using None explicitly (e.g. L[1:2:None]), and/or to give 3rd-party types the opportunity to handle 1 and None differently in their __getitem__/__setitem__/__delitem__ implementation.

Answered By: wim
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.