The slice operator enables you to capture a subset of data from an original list or string using the format
[start:stop:step]
.
Some popular use cases where I have used the slice operator include:
- Extracting year and/or month and/or day of the month from a string
- Extracting the zip code at the tail end of an address string
- Masking bank account or credit card numbers
- Extracting area code from phone numbers
Here is how the Python [:] operator can work when populating the values on either side of the colon:
Extract Date Values
>>> date_string = "2023-12-01"
>>> year = date_string[:4]
>>> year
'2023'
>>> month = date_string[5:-3]
>>> month
'12'
>>> dom = date_string[-2:]
>>> dom
'01'
As you can see from the above examples, populating the values for the
start
and/or
stop
values in the slice operator can produce results to help extract the necessary values from a string.
Extract Zip Code
>>> address = "123 Main Street, Anytown, CA 12345"
>>> zip_code = address[-5:]
>>> zip_code
'12345'
The slice operator can easily extract the trailing value from a string if the value extracted contains the same number of characters. There are times where it might be useful to apply the
.strip()
string method to ensure the string has been cleared of all trailing and leading whitespace characters, like so:
>>> address = " 123 Main Street, Anytown, CA 12345 "
>>> zip_code = address.strip()[-5:]
>>> zip_code
'12345'
Notice how the application of the
.strip()
string method helps to remove the trailing space before the slice operator extracts the last 5 characters from the string.
Mask Bank Account / Credit Card Numbers
>>> credit_card = "1234567890123456"
>>> masked_card = f"**** **** **** {credit_card[-4:]}"
>>> masked_card
'**** **** **** 3456'
Another handy use case for using the slice operator is to help mask numbers. This has come in handy when trying to display a bank account or credit card number back to the user for them to see what will be charged.
Extract Area Code From Phone Numbers
>>> phone_number = "123-456-7890"
>>> area_code = phone_number[:3]
>>> area_code
'123'
Whether it’s from the end, middle or start of a string, using the slice operator can help to extract the necessary details needed from a string; just ensure it’s in the proper format before performing the extraction.
But besides the above examples on using the slice operator to
extract
information from an original string or list, you can also use the slice operator for another purpose when
there are no values inserted into the
start
and
stop
sections
.
Use Python [:] To Create A New Object
One important thing to note is that the
[:]
notation is a form of slicing that creates a new object. This means that any modifications made to the new object will not affect the original sequence. This can be incredibly useful for creating subsets or copies of data without altering the original content. Additionally, the
[:]
notation can also take optional arguments such as step, allowing for more advanced slicing operations such as reversing a sequence or skipping elements.
The slice operator containing no values for the
start
and
stop
positions returns a complete copy of the original string or list. This is helpful when you want to perform a shallow copy of your list.
Besides using the built-in list method
.copy()
you can use this shortcut slice operator (a whole 4 characters less) in its place.
Let’s look at an example:
>>> a_list = [1, 2, 3]
>>> b_list = a_list
>>> a_list[0] = 100
>>> print(b_list)
[100, 2, 3]
The initial thought for those fresh to coding would be:
I thought I was just copying the
a_list
to a new variable
b_list
before
a_list
was modified, why did
b_list
change too?
This has to do with how variables are stored in memory. A way to demonstrate this is by looking at the built-in function
id()
and the reserved operator
is
.
>>> a_list = [1, 2, 3]
>>> b_list = a_list
>>> id(a_list)
4670898112
>>> id(b_list)
4670898112
>>> a_list is b_list
True
From the example above, you can see that the built-in
id()
function returns a reference number to each variable, and the id number for both variables is the same.
This means that the two variables are pointing to the same object in memory and are equivalent. The operator
is
performs this test on equivalency and returns
True
because both variables point to the same object reference.
Therefore, the point being made is that because each variable points to the same object, if you modify the object through either variable, it will mean the other variable changes, too.
>>> a_list = [1, 2, 3]
>>> b_list = a_list
>>> a_list[0] = 10
>>> b_list[1] = 20
>>> print(a_list)
[10, 20, 3]
>>> print(b_list)
[10, 20, 3]
>>> id(a_list)
4369259008
>>> id(b_list)
4369259008
As you can see both variables return the same result because they both point to the same object.
But what if you don’t want this? What if you want to capture a copy of
a_list
before it changes?
How To Make A Shallow Copy Of A List
One way to do this is to create a
shallow copy
of your list using the
[:]
slice operator.
Let’s look at our previous example again, but this time will use the slice operator at the opportune moment:
>>> a_list = [1, 2, 3]
>>> b_list = a_list[:]
>>> a_list[0] = 100
>>> print(a_list)
[100, 2, 3]
>>> print(b_list)
[1, 2, 3]
>>> id(a_list)
4369256192
>>> id(b_list)
4369259008
>>> a_list is b_list
False
Notice the difference here?
In the code example above the
a_list
is created and the
b_list
is created as a copy of
a_list
before any changes are made to the original
a_list
list. Then when a change is made to
a_list
it does not change
b_list
and we can check that these are different by inspecting their object id references, which are both different.
What Is A “Shallow Copy”?
A shallow copy performs a copy of the original list, but keeps the same id references from the original list. If you were to inspect the id of each object in the list they would return their unique id:
>>> a_list = [{'a': 1}, 2]
>>> id(a_list[0])
4368574528
>>> id(a_list[1])
4365461840
>>> id(a_list)
4369259008
As you can see the list has a unique id and each element within the list has its own unique id. When you make a shallow copy of this list using the slice operator
[:]
you are keeping all the same references of the original:
>>> b_list = a_list[:]
>>> id(b_list[0])
4368574528
>>> id(b_list[1])
4365461840
>>> id(b_list)
4365778496
>>> a_list is b_list
False
The only difference above with the original
a_list
example is that the id reference of
b_list
is different. Even though both lists contain the exact same references and values the equivalency test returns
False
because the variable id references are not the same.
If you look at the dictionary which was inserted into the first element of the
a_list
what would happen if this changed?
>>> a_list[0]['a'] = 100
>>> print(b_list[0])
{'a': 100}
>>> a_list[1] = 200
>>> print(b_list[1])
2
Notice how by changing the dictionary of the first element it changed the first element in the
b_list
, whereas when the second element was reassigned to a new value, it did not change the second element in the
b_list
.
This is why we call the shortcut copy method
[:]
a
shallow copy
. There are some elements, such as a dictionary, which, if changed in the original list, will modify the elements in the copied list because a shallow copy creates a new variable but retains the same reference IDs of the original list.
Reverse The Order
Besides creating an exact replica in the
same order
as the original object, you can also apply the reversing feature using the slice operator without needing to use the
.reverse()
method.
Here’s an example demonstrating this idea:
>>> a_list = [1, 2, 3, 4, 5]
>>> b_list = a_list[::-1]
>>> b_list
[5, 4, 3, 2, 1]
This feature of the slice operator can make it easier to reverse the order of the original list if needed.
Python [:] Operator
A shortcut way to copy a list or a string is to use the slice operator
[:]
. This will make a shallow copy of the original list, keeping all object references the same in the copied list. This may work well for lists that are completely reassigned to new values but would not work well if elements within the original list are modified, and these elements are dictionaries.
The built-in list method
.copy()
performs the exact same task as the empty slice operator
[:]
but the slice operator does so with fewer characters, hence why it’s deemed to be a shortcut approach to copying.