slicing
python

How slicing in Python works

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

Slicing is one of Python's most useful sequence features because it lets you select a range of items with very compact syntax. Once you understand how start, stop, and step interact, slices become predictable instead of magical.

The Core Rule

The general form is:

python
sequence[start:stop:step]

Python interprets that as:

  • Start at start
  • Move in increments of step
  • Stop before reaching stop

The most important detail is that stop is exclusive. That rule is why items[2:5] returns the elements at indices 2, 3, and 4, but not index 5.

python
1items = [10, 20, 30, 40, 50, 60]
2
3print(items[2:5])   # [30, 40, 50]
4print(items[:3])    # [10, 20, 30]
5print(items[3:])    # [40, 50, 60]
6print(items[:])     # full shallow copy

Defaults and Negative Indices

If you omit start, Python uses the beginning of the sequence for a positive step. If you omit stop, Python uses the end. Negative indices count from the end of the sequence, where -1 means the last element.

python
1word = "slicing"
2
3print(word[1:4])    # lic
4print(word[-3:])    # ing
5print(word[:-1])    # slicin
6print(word[-5:-2])  # ici

Negative indices are just offsets from the end; they do not automatically reverse anything.

How step Changes the Slice

The step controls how far Python jumps between selected elements. A step of 2 means every second item. A negative step means traverse the sequence in reverse.

python
1numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8]
2
3print(numbers[::2])    # [0, 2, 4, 6, 8]
4print(numbers[1::2])   # [1, 3, 5, 7]
5print(numbers[::-1])   # reversed copy
6print(numbers[7:2:-2]) # [7, 5, 3]

When the step is negative, the direction flips, so the start index should usually be to the right of the stop index. If those directions do not line up, the result is just an empty sequence.

Slice Objects Exist Explicitly

The bracket syntax is shorthand for a slice object. Python lets you create one directly and reuse it.

python
1data = ["a", "b", "c", "d", "e", "f"]
2middle = slice(1, 5, 2)
3
4print(data[middle])  # ['b', 'd']

This becomes useful when the same slicing rule appears in several places, or when an API expects a slice object explicitly.

Slicing Returns a New Sequence

For built-in types such as lists, tuples, and strings, slicing returns a new object rather than a view into the original sequence.

python
1original = [1, 2, 3, 4]
2copy_part = original[1:3]
3copy_part[0] = 99
4
5print(original)   # [1, 2, 3, 4]
6print(copy_part)  # [99, 3]

That is why items[:] is a common shallow-copy pattern for lists.

One subtle point is that the copy is shallow. If the list contains nested mutable objects, those inner objects are still shared.

Slice Assignment on Lists

Lists support slice assignment, which lets you replace a whole range at once.

python
1values = [1, 2, 3, 4, 5]
2values[1:4] = [20, 30]
3print(values)  # [1, 20, 30, 5]
4
5values[::-1] = values
6print(values)  # [5, 30, 20, 1]

This is powerful, but it is specific to mutable sequences like lists. Strings and tuples do not support slice assignment because they are immutable.

Why Out-of-Range Slices Do Not Crash

Python clamps slicing boundaries gracefully. Asking for more than exists simply returns what is available.

python
1nums = [1, 2, 3]
2
3print(nums[0:10])   # [1, 2, 3]
4print(nums[10:20])  # []
5print(nums[-10:2])  # [1, 2]

That behavior is different from indexing a single element, where nums[10] raises IndexError.

Common Pitfalls

The most common mistake is forgetting that stop is exclusive. If you want the first five elements, the correct slice is items[:5], not items[:4].

Another issue is using a negative step with start and stop in the wrong order. items[2:7:-1] returns an empty result because Python cannot walk backward from 2 toward 7.

People also confuse slicing with deep copying. items[:] creates a new outer list, but nested mutable objects are still shared.

Finally, do not assume slicing is lazy. For built-in sequences, slicing usually allocates a new object, which can matter for large data structures.

Summary

  • Python slicing follows sequence[start:stop:step].
  • The stop bound is exclusive, which is the key rule to remember.
  • Negative indices count from the end, and negative steps reverse traversal.
  • Slicing built-in sequences returns a new object, usually a shallow copy.
  • List slicing also supports assignment, making it useful for in-place range updates.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.