When using the slice operator
[start:stop:step]
to capture only a subset of data from an original list or string, what does
[:]
do?
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.
Summary
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 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 less characters, hence why it’s deemed to be a shortcut approach to copying.