Slicing in Python: The slice() Function & [::] Notation

Slicing in Python means accessing a subsection of an iterable, such as a string or a list.

For example, let’s get the 3 first elements from a list as a slice:

nums = [-1, -2, -3, 10, 100, 1000]
first_three = nums[0:3]

print(first_three)

This returns the three elements in a list:

[-1, -2, -3]

Generally, the slicing follows this syntax:

iterable[start:stop:stepsize]

Where:

  • start is the starting index. Defaults to the first element.
  • stop is the index until which values are sliced. Defaults to the last element.
  • stepsize is how many items to jump over. Defaults to 1.

Slicing in Python can be used to access, modify, and delete subsequences of iterables.

This guide teaches you how to slice iterables, such as lists in Python. The theory is backed up with great examples.

Python Indexing

In Python, you can access an element in a sequence with an index. This index is an integer that represents the position of that particular element.

In case you are unfamiliar with indexing or negative indexing, please read this section before heading to the slicing part.

Zero-Based Indexing in Python

In Python, indexing starts from zero.

This means the first element has an index of zero, and the second element has an index of one, and so on.

Here is an illustration:

Positive indexing of a list of names in Python

How to Use the Index to Access Elements in Python

Now that you know what indexing means, let’s take a look at how to use indexes to get values from sequences.

In Python, you can access the nth element of an iterable, such as a list, with an index. To do this, use the square bracket operator by passing the index as an argument.

For instance, let’s create a list of numbers, and let’s access the 2nd and the 3rd element of it:

nums = [10, 100, 1000, 10_000, 100_000]

second = nums[1]
third = nums[2]

print(second, third)

Output:

100 1000

As you can see, the 2nd argument goes with an index of 1, and the 3rd one with an index of 2.

Indexing is not limited to lists only. It also works for strings and tuples.

Here are examples:

# First letter of a string
greeting = "Hello world!"
first_letter = greeting[0]
print(first_letter) # Prints 'H'

# z-cooridnate of a 3D tuple
coords = 0, 2, 9
z = coords[2]
print(z) # Prints 9

Negative Indexing in Python

Python also supports negative indexing. This way of indexing starts at the end of the iterable, such as a list.

Unlike (positive) indexing, negative indexing does not start from 0. Instead, it starts from -1, where -1 is the last element (the right-most one). Then -2 is the second last and so on.

Here is an illustration of negative indexing in Python:

Negative indexing of a list of names in Python

For example, let’s access the last and the first element of a list with negative indexing:

nums = [10, 100, 1000, 10_000]

last = nums[-1]
first = nums[-4]

print(last, first)

Output:

10000 10

Similar to positive indexing, negative indexing works with tuples and lists as well.

For instance:

# Last letter of a string
greeting = "Hello world!"
last_letter = greeting[-1]
print(last_letter) # Prints '!'

# z-cooridnate of a 3D tuple
coords = 0, 2, 9
z = coords[-1]
print(z) # Prints 9

Now you have a basic understanding of how indexing works in Python.

Next, let’s move on to slicing, which is heavily related to indexing.

Slicing Iterables in Python

Python slicing allows you to access a range of elements from an iterable. For instance, you can get the first three numbers from a list of numbers with slicing.

Slicing in Python is based on zero-based indexing.

The syntax of slicing is as follows:

iterable[start:stop:stepsize]

This syntax is called the indexing syntax of slicing. (Later on, you will learn an alternative syntax.)

Where:

  • start marks the starting index of the slice. Defaults to the beginning of a list.
  • stop marks the end of the slice. Represents the first value that is not selected to the slice. Defaults to returning the rest of the list.
  • stepsize specifies how many elements to jump over. Defaults to 1.

Example 1. Let’s access the 2nd, 3rd, and 4th elements of a list.

To do this, you need to

  • Start slicing from the 2nd element (1 index).
  • Stop slicing before the 5th element (4 index).
  • Step over 1 value at a time.

Here is how it looks in the code:

names = ["Alice", "Bob", "Charlie", "David", "Emmanuel"]
part = names[1:4:1]

print(part)

Output:

['Bob', 'Charlie', 'David'

As the step size is 1 by default, you do not need to write it separately. Instead, you could have written names[1:4].

Example 2. Let’s access the first three elements of a list.

To do this, you need to

  • Start slicing from the beginning of the list.
  • Stop slicing before the 4th element (3 index).
  • Step over 1 value at a time.

But as you already know, the start means starting from the beginning by default. Also, the stepsize is 1 by default. So we can omit both of those.

Here is how it looks in the code:

names = ["Alice", "Bob", "Charlie", "David", "Emmanuel"]
part = names[:3]

print(part)

Output:

['Alice', 'Bob', 'Charlie']

Example 3. Let’s get every third element of a list.

To do this:

  • Start slicing from the beginning.
  • Stop slicing at the end.
  • Step over 3 values.

As you start from the beginning and end at the end, you do not need to specify the start and stop parameters. The only thing left is the stepsize, which needs to be set 3.

Here is how it looks in the code:

nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
every_third = nums[::3]

print(every_third)

Output:

[1, 4, 7, 10]

Negative Slicing in Python

In Python, similar to negative indexing, you can use negative slicing. This means you access a range of values by using negative indexes as start and stop parameters.

Negative slicing follows the same syntax as positive slicing with parameters start and stop being negative.

iterable[start:stop:stepsize]

By the way, you can also define a negative stepsize to go backward when slicing.

Example 1. let’s get the last three elements from a list.

To do this, you need to:

  • Start slicing at the 3rd last element (-3 index).
  • Stop at the end of the list.
  • Step over 1 value at a time.

This means you only need to specify the start parameter at -3 when slicing. This makes the slice start from -3 and automatically go through the rest of the list.

Here is how it looks:

names = ["Alice", "Bob", "Charlie", "David", "Emmanuel"]
part = names[-3:]

print(part)

Output:

['Charlie', 'David', 'Emmanuel']

Example 2. Reverse a list of numbers.

To do this, you can use slicing.

  • Start from the end of the list.
  • Stop at the beginning of the list.
  • Step backward 1 value at the time (-1 stepsize).

In other words, you do not need to specify the start or stop parameters. The only thing you need to specify is the stepsize of -1 to start from the end and end from the start.

Here is how it looks in the code:

nums = [1, 2, 3, 4, 5]
every_third = nums[::-1]

print(every_third)

Output:

[5, 4, 3, 2, 1]

Now you understand how slicing works in Python using indexing syntax.

Alternatively, you can use built-in slice objects when slicing iterables.

Slice Objects in Python

In Python, there is a built-in type called a slice.

To create a slice object, use the built-in slice() function with the following syntax:

slice_obj = slice(start, stop, end)

Where:

  • start is the starting index at which slicing starts. Defaults to None.
  • stop is the ending index until which the slicing continues. Slicing stops at stop – 1.
  • stepsize is the number of items to jump over when slicing. Defaults to None.

The point of a slice object is you can replace the indexing for slicing (iterable[start:stop:end]) with iterable[slice_obj] to slice an iterable.

Let’s jump back to one of the previous examples where we retrieved the 2nd, 3rd, and 4th elements from a list:

names = ["Alice", "Bob", "Charlie", "David", "Emmanuel"]
part = names[1:4:1]

print(part)

Here you used the slicing syntax where you define the start, stop, and stepsize directly inside the square brackets.

Now, instead of doing it this way, let’s use a slice object:

names = ["Alice", "Bob", "Charlie", "David", "Emmanuel"]

s = slice(1, 4, 1)
part = names[s]

print(part)

Output:

['Bob', 'Charlie', 'David']

As you can see, this results in the exact same outcome.

You can use a slice object to slice a list any way you want. But instead of omitting start, stop, or stepsize, use None.

For example, let’s reverse a list with a slice object:

names = ["Alice", "Bob", "Charlie", "David", "Emmanuel"]

s = slice(None, None, -1)
reversed = names[s]

print(reversed)

Output:

['Emmanuel', 'David', 'Charlie', 'Bob', 'Alice']

Here the slice(None, None, -1) behaves the same way as ::-1.

When Use Slicing in Python

Slicing is useful if you want to access, modify, or delete parts of an iterable.

Let’s see some examples of each use case.

Access Elements with Slicing in Python

Accessing ranges of elements with slicing is a popular use case for slicing.

In this guide, you have already seen dozens of examples of accessing parts of iterables with slicing.

For example, let’s get the first three values from a tuple:

nums = 1, 2, 3, 4, 5
first_three = nums[:3]

print(first_three)

Output:

(1, 2, 3)

A very common application of accessing iterables with slicing is to reverse an iterable in Python.

For example, let’s reverse a string:

word = "Hello"
rev = word[::-1]

print(rev)

Output:

olleH

Modify Elements with Slicing in Python

Sometimes you may want to modify a range of items in a sequence. Instead of modifying the values separately or using a for loop, you can utilize slicing.

As a simple example, let’s replace two first elements of a list with another two:

nums = [1, 2, 3, 4, 5, 6]

nums[:2] = [10, 20]

print(nums)

Output:

[10, 20, 3, 4, 5, 6]

As a slightly more advanced example, let’s turn every second number negative in a list of numbers:

nums = [1, 2, 3, 4, 5, 6]

nums[::2] = [-n for n in nums[::2]]

print(nums)

Output:

[-1, 2, -3, 4, -5, 6]

Delete Elements with Slicing in Python

You can use slicing to get rid of ranges of items in an iterable. To do this, use the built-in del statement on a slice.

For instance, let’s delete every second element in a list:

nums = [1, 2, 3, 4, 5, 6]

del nums[::2]

print(nums)

Output:

[2, 4, 6]

Conclusion

Today you learned how slicing works in Python.

To recap, slicing means accessing multiple elements in an iterable at once. Slicing returns a subsequence of the original one.

There are two ways you can slice an iterable:

  • Use the indexing syntax of slicing (iterable[start:stop:stepsize])
  • Using a slice object (iterable[slice(start, stop, stepsize)])

You can use slicing to access and modify/delete ranges of elements in an iterable.

A common example of slicing is reversing an iterable.

For example:

word = "Hey"

rev = word[::-1]

print(rev)

Output:

yeH

Thanks for reading. Happy coding!

Further Reading

Python Interview Questions