Explaining ‘[:]’ in Python

Pavol Kutaj
3 min readSep 27, 2022

--

This is part of the educational quest to finish Leetcode’s Explore Card Introduction to Data Structure Array and String. See how my quest is going at CODE QUEST > Leet Code > Introduction to Data Structure: Array and String (AAS)

The aim of this page📝 is to overcome my initial misunderstanding of the last line of the following

def rotate_arrat(nums:List[int], k:int) -> None:
n = len(nums)
a = [0] * n
for i in range(n):
a[(i + k) % n] = nums[i]
nums[:] = a <<<<<<<<<<<<<<<<

…which is the second official solution to the wonderful Rotate Array > LeetCode puzzle.

[:] SYNTAX EXPLAINED

  • [:] syntax belongs to slicing feature of python list
  • [:] syntax selects all items of the sliced list
  • [:] syntax is used idiomatically. Why? Because of the Python Object Model
  • [:] syntax is not used that much in the wild as far as I've been reading through other people's code (wrong?)
  • [:] syntax is used as a list assignment technique, i.e. in combination with = operator
  • [:] syntax is, confusingly perhaps, possible to use both on the left and the right side of an assignment statement
# BOTH SYNTACTICALLY VALID:
l[:] = l2
l2 = l[:]
  • Without going too deep into the weeds here, I want to stress that it matters on which side of the assignment you see [:]
  • Again, I find this confusing/risky

LET’S FIRST FORGET FORGET ABOUT [:]

  • Also, I am not going too deep into Python Object Model, however, you need to understand some of it for the following to make sense
  • In summary, if you have say a list l with values [1,2,3,4] and you assign that list to another list l2, the two names will refer to/share the same list object
  • You can check the object id with the built-in id function
>>> l = l2 = [1,2,3,4]

>>> id(l)
106046568

>>> id(l2)
106046568

>>> id(l) == id(l2)
True
  • Because lists are mutable — which is of the essence here — the objects are not recreated upon modification
  • Therefore, if you modify l, you also modify l2 — which is extremely dangerous
>>> l
[1, 2, 3, 4]

>>> l2
[1, 2, 3, 4]

>>> l.append(5)

>>> l2
[1, 2, 3, 4, 5]

[:] ON THE RIGHT OF =: COPY

  • Therefore, if you want to copy a list you cannot just do new_list = old_list
  • We need to create a new_list as a new object
  • For this, we are utilizing the so-called colon copy with the use of slicing
  • The syntax is
new_list = old_list[:]
  • With the example from above, see that the lists are not identical and therefore the modification of the old list does not affect the new list
>>> old_list = [1,2,3,4]

>>> new_list = old_list[:]

>>> id(old_list)
87148616

>>> id(new_list)
99036456

>>> old_list.append(5)

>>> old_list
[1, 2, 3, 4, 5]

>>> new_list
[1, 2, 3, 4]
  • Note that this is a shallow copy, meaning that the lists are referring to are still sharing elements
  • This means that if you change the first element of the list in the old list, it will be changed also in the new list
  • But most of the time, a shallow copy is enough

[:] ON THE LEFT OF =: REPLACE

  • this is an entirely different usecase with dangerously similar syntax
  • say that you have a list l with values [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  • with the following function nothing happens to the values of l outside of the function
>>> l = list(range(10))

>>> def re_assign(l):
... l2 = [1,2,3,4]
... print("old id: ", id(l))
... l = l2
... print("new id: ", id(l))
... return l

>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]


>>> re_assign(l)
old id: 109195048
new id: 99638600
[1, 2, 3, 4]


>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  • the [:] on the left of an assignment does in_place replacement
  • this means you are keeping the ID
  • this means — dangerously — that you are changing the value of l also outside of the function - can be dangerous for the caller!
>>> l = list(range(10))

>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> def in_place(l):
... l2 = [1,2,3,4]
... print("old id :", id(l))
... l[:] = l2
... print("still the same id:", id(l))
... return l

>>> in_place(l)
old id : 108260840
still the same id: 108260840
[1, 2, 3, 4]

>>> l
[1, 2, 3, 4]

SOURCES

--

--

No responses yet