In Python, we can extract a portion of a sequence (lists, strings, tuples etc.) using the slicing operation.
Suppose you have a PDF file and need only its name without the .pdf extension. You can use slicing to extract just that portion of the string.
In this tutorial, we'll mostly use slicing on strings, but the same concept applies to lists, tuples, and other sequences.
Slicing Syntax
The syntax of slicing is:
seq[start:stop:step]
where,
seqis a sequence such as a string, list etc.startis the index (inclusive) where slicing starts.stopis the index (exclusive) where slicing stops.stepis the interval between items. Its default value is 1.
Slicing from Start to Stop
Let's see how slicing works without passing step, like seq[start:stop]. The default value of step is 1, which will be used automatically.
text = "catalog.pdf"
# Extract items from index 0 up to (not including) index 7
print(text[0:7]) # Output: catalog
# Extract items from index 1 up to (not including) index 4
print(text[1:4]) # Output: ata
# Extract items from index 2 up to (not including) index 4
print(text[2:4]) # Output: ta
# Extract items from index -5 up to (not including) index -2
print(text[-5:-2]) # Output: g.p
Read text[1:4] as: start at index 1, go up to (but not including) index 4, and take every character. It's important to note that the start index is inclusive (1 is included) but the stop index is exclusive (4 is not included).
Negative start and stop indices work the same way, except they count from the end of the sequence (index -1 is the last item).
Read text[-5:-2] as: start at index -5, go up to (but not including) index -2.
Slicing with Step
By default, the value of step is 1. This means text[1:4] is equivalent to text[1:4:1], and slicing moves through the sequence one item at a time.
Let's see what happens with different steps.
text = "ABCDEFGH"
# Extract items from index 1 up to index 7, every 2nd item
print(text[1:7:2]) # Output: BDF
# Extract items from index 0 up to index 7, every 3rd item
print(text[0:7:3]) # Output: ADG
# Extract items from index -6 up to index -2, every 2nd item
print(text[-6:-2:2]) # Output: CE
Read text[1:7:2] as: start at index 1, go up to (but not including) index 7, and take every second character.
Can you read text[-6:-2:2] in a similar way and make sense of it?
Negative Step
A negative step makes the slice move from right to left (in reverse order). This is useful in many situations. Note that with a negative step, start should be greater than stop to get a non-empty result.
text = "ABCDEFGH"
# Reverse slice: index 6 down to index 1
print(text[6:1:-1]) # Output: GFEDC
# Reverse slice: index -3 down to index -6, every 2nd item
print(text[-3:-6:-2]) # Output: FD
Omitting Start and Stop Index
If we omit the start index, slicing starts from the beginning of the sequence. And if we omit the stop index, slicing goes up to the end of the sequence. If we omit both, we get a copy of the entire sequence.
text = "Python"
# Omit stop: from index 2 to the end
print(text[2:]) # Output: thon
# Omit start: from the beginning up to index 4
print(text[:4]) # Output: Pyth
# Omit both: the entire sequence
print(text[:]) # Output: Python
Read text[2:] as: start at index 2 and go all the way to the end.
Read text[:4] as: start from the beginning and go up to (but not including) index 4.
Read text[:] as: take everything from start to end.
Example: Copying a List
As you know, we use the copy() method to copy a list. Instead of using copy(), we can also use slicing with both indices omitted, like numbers[:], to create a copy.
numbers = [1, 2, 3, 4, 5]
# Create a copy of the list
copy = numbers[:]
print(copy) # Output: [1, 2, 3, 4, 5]
# Modifying the copy list doesn't affect the original
copy[0] = 100
print(copy) # Output: [100, 2, 3, 4, 5]
print(numbers) # Output: [1, 2, 3, 4, 5]
Here, numbers[:] creates a new list containing all the items of numbers. Since it's a separate list, changes made to copy don't affect the original numbers list.
Example: Reversing a Sequence Using Slicing
A common use of a negative step is reversing a sequence. If we omit both start and stop and set step to -1, slicing occurs from right to left with each item included, giving us the sequence in reverse order.
text = "Python"
# Reverse the string
print(text[::-1]) # Output: nohtyP
numbers = [1, 2, 3, 4, 5]
# Reverse the list
print(numbers[::-1]) # Output: [5, 4, 3, 2, 1]
Read text[::-1] as: start from the end, go all the way to the beginning, taking every item.
Since step is negative, the default start becomes the last item and the default stop becomes just before the first item.
How slicing Works Internally
Under the hood, when we use slicing, Python translates the slice syntax into a slice() object and passes it to the __getitem__() method.
So numbers[:] is equivalent to numbers.__getitem__(slice(None, None)), and numbers[1:4] is the same as numbers.__getitem__(slice(1, 4)). You can learn more about the slice() function here.