Python List Slicing: Syntax, Examples, and a Visualizer
Table of Contents
Python list slicing extracts part of a list with the list[start:stop:step] syntax. It can grab the first few items, skip every other item, work backward, or copy the entire list.
All the content from our Boot.dev courses is available for free here on the blog. This guide comes from the "Lists" chapter of Learn Python for Beginners, where you can practice slicing lists in the interactive editor.
Python List Slicing Syntax
Python makes it easy to slice and dice lists to work only with the section you care about. The slice notation has three optional parts:
my_list[start:stop:step]
| Part | What It Controls | Default When step > 0 |
|---|---|---|
start |
The first index included in the slice | Index 0 |
stop |
The first index excluded from the slice | Just after the last item |
step |
How far to move between selected indexes | 1 |
For example:
scores = [50, 70, 30, 20, 90, 10, 50]
print(scores[1:5:2]) # [70, 20]
The slice starts at index 1, stops before index 5, and moves 2 indexes at a time. It selects the values at indexes 1 and 3.
A normal slice returns a new list, so the original stays unchanged.
Try the List-Slicing Visualizer
Adjust start, stop, and step below. The highlighted indexes show which values Python puts in the new list.
The visualizer uses the same rules as Python's slice syntax. You can run the examples yourself in the free Python playground.
Omit Start, Stop, or Step
All three sections are optional. Leave out start to begin at the front of the list, or leave out stop to continue through the end:
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numbers[:3]) # [0, 1, 2]
print(numbers[3:]) # [3, 4, 5, 6, 7, 8, 9]
Leave out both bounds and provide only a step to select items across the full list:
print(numbers[::2]) # [0, 2, 4, 6, 8]
The empty fields don't mean zero. They tell Python to use the appropriate end of the list, which matters when the step is negative.
Negative Indexes and Steps
Negative indexes count from the end of the list. -1 is the last item, -2 is the second-to-last item, and so on:
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print(numbers[-3:]) # [7, 8, 9]
A negative step moves backward. Omitting both bounds with a step of -1 selects the entire list in reverse:
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print(numbers[7:1:-2]) # [7, 5, 3]
When the step is negative, an omitted start defaults to the last item and an omitted stop goes just before the first item. The second slice starts at index 7, moves backward by 2, and stops before index 1. If the step points the wrong direction for the bounds, the result is empty:
print(numbers[1:7:-1]) # []
Why the Stop Index Is Exclusive
Like range(), a slice includes start and excludes stop. numbers[2:5] selects indexes 2, 3, and 4.
The exclusive stop makes adjacent slices fit together without overlap:
numbers = [0, 1, 2, 3, 4, 5]
first_half = numbers[:3]
second_half = numbers[3:]
print(first_half + second_half) # [0, 1, 2, 3, 4, 5]
The first slice stops exactly where the second starts. No special + 1 adjustment is needed.
Out-of-Range Bounds Are Safe
A single out-of-range list index raises an IndexError, but slice bounds are clamped to the list's valid range:
players = ["Frodo", "Aragorn", "Legolas"]
print(players[1:99]) # ['Aragorn', 'Legolas']
print(players[99:]) # []
print(players[-99:99]) # ['Frodo', 'Aragorn', 'Legolas']
This makes slices convenient when the list's length can vary. A step of 0 is different: Python raises a ValueError because it can't move through the list zero indexes at a time.
Slicing Makes a Shallow Copy
Reading a slice creates a new list! Selecting the full range with [:] is one of the easiest ways to make a shallow copy:
players = ["Frodo", "Aragorn"]
copied_players = players[:]
copied_players.append("Legolas")
print(players) # ['Frodo', 'Aragorn']
print(copied_players) # ['Frodo', 'Aragorn', 'Legolas']
The outer list is new, but Python doesn't recursively copy nested mutable values:
parties = [["Frodo"], ["Aragorn"]]
copied_parties = parties[:]
copied_parties[0].append("Sam")
print(parties[0]) # ['Frodo', 'Sam']
You can use copy.deepcopy() when the nested values need to be independent too. For a slice containing k items, copying takes O(k) time and O(k) extra space.
Slice Assignment Changes the Original List
Okay, so we know a slice on the right side of a = assignment reads part of a list, but a slice on the left side replaces that range in the original list:
players = ["Aragorn", "Boromir", "Denethor", "Eowyn"]
players[1:3] = ["Sam", "Gimli", "Legolas"]
print(players) # ['Aragorn', 'Sam', 'Gimli', 'Legolas', 'Eowyn']
The replacement can contain a different number of items, so slice assignment can change the list's length. Python also lets you delete a slice with the del keyword.
A stepped slice is stricter. If the assignment uses a step other than 1, the replacement must contain exactly as many items as the slice selects. Python raises a ValueError instead of resizing the list when those lengths differ.
Use a Step to Split Alternating Items
A step of 2 selects every other item (meaning they alternate). Change the starting index to split one list into even-indexed and odd-indexed groups:
players = ["Frodo", "Aragorn", "Legolas", "Gimli", "Sam", "Eowyn"]
even_team = players[::2]
odd_team = players[1::2]
print(even_team) # ['Frodo', 'Legolas', 'Sam']
print(odd_team) # ['Aragorn', 'Gimli', 'Eowyn']
The first team contains indexes 0, 2, and 4. The second contains indexes 1, 3, and 5. Zero is an even number, so players[::2] starts with the first item.
The same pattern works when the list has an odd length, because the even-indexed group gets the extra item. Our Python practice problems article includes more list-related exercises when you're ready to practice!
Frequently Asked Questions
What does [::] mean in Python?
The full slice syntax is list[start:stop:step]. With all three fields empty, numbers[::] makes a shallow copy of the whole list. A value in the final field controls the step, so numbers[::2] returns every second item.
Is the stop index inclusive in Python list slicing?
No. The start index is included, but the stop index is excluded. A slice from index 1 to index 4 returns the items at indexes 1, 2, and 3.
Does slicing a Python list create a copy?
Yes. Reading a list slice creates a new list containing references to the selected items. It is a shallow copy, so nested mutable objects are still shared.
Can Python list slices go out of range?
Yes. Python clamps slice bounds to the list instead of raising an IndexError. A slice that starts beyond the end returns an empty list.
How do negative steps work in Python slicing?
A negative step moves backward through the list. The stop bound is still excluded, and omitting both bounds with a step of -1 reverses the list.
