Back to Blog
Python

Python Slice Syntax: A Practical Reference

python slice syntax: Learn Python slice syntax for lists, strings, and other sequences. Master start, stop, step, negative indices, and slice objects with practical ex...

slicingsequenceslistsstringsstepnegative-indices
Diagram showing Python slice syntax with start, stop, and step on a sequence

Python slice syntax is the mechanism for extracting a portion of a sequence—such as a list, tuple, or string—using the form sequence[start:stop:step]. This syntax is used constantly in data processing, algorithm implementation, and everyday scripting. Understanding how the indices are interpreted, especially with negative values, prevents off-by-one errors and makes code more readable.

The Basic Slice Syntax: start, stop, and step

The core of slicing is the expression sequence[start:stop:step]. Each part is optional, and the default behavior depends on the sign of the step. When step is positive, the slice starts at start (inclusive) and goes up to but not including stop, moving forward. When step is negative, the slice starts at start and moves backward, with stop again exclusive.

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(numbers[2:5]) # [2, 3, 4] print(numbers[:3]) # [0, 1, 2] print(numbers[7:]) # [7, 8, 9] print(numbers[::2]) # [0, 2, 4, 6, 8]

The first example selects indices 2, 3, and 4. Omitting start defaults to the beginning of the sequence, and omitting stop defaults to the end. The ::2 step selects every second element.

Negative Indices and How They Map

Negative indices count from the end of the sequence. -1 refers to the last element, -2 to the second-to-last, and so on. This is particularly useful when you need to access elements relative to the end without knowing the sequence length.

text = "hello" print(text[-1]) # 'o' print(text[-3:]) # 'llo' print(text[:-1]) # 'hell'

When using negative indices in a slice, the same exclusivity rule applies: the stop index is not included. For example, text[-3:-1] returns 'll', not 'llo'. A common mistake is expecting text[-3:-1] to include the last character, but it does not.

Slicing with Step Values and Reversing

The step parameter controls how many elements are skipped. A positive step moves forward; a negative step moves backward. Setting step to -1 reverses the sequence.

numbers = [1, 2, 3, 4, 5] print(numbers[::-1]) # [5, 4, 3, 2, 1] print(numbers[4:1:-1]) # [5, 4, 3]

The second example starts at index 4 (the last element) and moves backward to index 2 (since index 1 is exclusive). This is a common pattern for extracting a reversed subrange. Note that when the step is negative, the default start becomes the end of the sequence and the default stop becomes the beginning.

Using slice Objects for Reusable Slices

If the same slice pattern is used repeatedly, you can create a slice object and reuse it. This improves readability and reduces duplication.

slice_obj = slice(2, 8, 2) data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(data[slice_obj]) # [2, 4, 6]

The slice constructor accepts start, stop, and step arguments, all of which can be None. This is especially useful when you need to pass a slice as a parameter to a function or store it as a configuration value.

Slicing Strings, Tuples, and Other Sequences

Slicing works on any sequence type that supports the sequence protocol, including strings, tuples, and range objects. The result type matches the original: slicing a string returns a string, slicing a tuple returns a tuple, and slicing a range returns a new range object.

tuple_data = (10, 20, 30, 40) print(tuple_data[1:3]) # (20, 30) range_data = range(10) print(range_data[2:5]) # range(2, 5)

This behavior is important when you need to preserve the original type. For example, if you are processing a string and use slicing to extract a substring, you can continue to use string methods on the result.

Memory and Performance Implications of Slicing

A slice creates a new object that copies the referenced elements. For lists and strings, this means the slice operation has a time and memory cost proportional to the length of the slice. If you are repeatedly slicing a large sequence, the overhead can become significant.

big_list = list(range(1_000_000)) # This copies 500,000 elements into a new list half = big_list[:500_000]

For read-only access, consider using itertools.islice to avoid copying when you only need to iterate over a portion. However, islice does not support negative indices or step values, so it is not a direct replacement for all slicing use cases.

Common Mistakes and How to Avoid Them

One frequent error is confusing the exclusive stop index. When you want the first five elements, you write sequence[:5], not sequence[:4]. Another mistake is using a negative step without adjusting start and stop correctly. For example, sequence[0:-1:-1] returns an empty list because the start is at index 0 and the step moves backward, so no elements are selected.

data = [1, 2, 3, 4] print(data[0:-1:-1]) # []

To reverse the entire sequence, use data[::-1]. To get a reversed subrange, specify the start and stop as indices that make sense with the negative step. If you need to copy a list, use data[:] rather than assigning the reference directly.

python slice syntax: Practical Usage and Code Examples | RYUSLOG DEV