Slicing a piece of python

Python is one of the most easy to use language with many small shortcuts for complex operations. One such example is slicing which I heavily use.

For example

a = [1,2,3,4,5,6]
print(a[1:4])
>>> [2, 3, 4]

I was intrigued as to how they work internally and decided to dig bit deeper. Slicing can be used to get sublist or substring. The numbers inside the square brackets are used as arguments to function slice(start=None, stop, step=None) which represents a set of indices specified by range(start, stop, step). Start and step are optional parameters and slice function uses the default values of 0, len(a) and 1 . If step negative the default value of start is -1 and stop is -len(a)

a[1:3] == a[1:3:1] # returns true 
a[:] == a[0:len(a):1] # returns true
>>> slice()
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
TypeError: slice expected at least 1 arguments, got 0
>>> slice(1)
slice(None, 1, None)

Similar to range() function element index=stop is ignored. While slice is not iterable on its own, itertools.islice() returns an iterator.

a[slice(i,j)] does not change the contents of the list a but creates a new list based on indices in slice(i,j). So you can use a[:] to create a deep copy of your list.

>>> print(id(a))
4373708744
>>> print(id(a[:])) #created a deep copy of a
4373883072

Slicing for assignment

Slicing can also be used in python for assignment.

a = [1,2,3,4,5]
a[1:1] = [8,9]
print(a)
>>>[1, 8, 9, 2, 3, 4, 5]
a = [1,2,3,4,5]
a[1:2] = [10,11]
print(a)
>>>[1, 10, 11, 3, 4, 5]

This can be confusing in the beginning but numbers inside square bracket come up with indices for at which the assignment takes place. So, a[1:1] returns the empty list between 1 and 2which is replaced by [8,9]. Similarly in second example a[1:2] returns list [2] which is replaced by list [10,11].

We can use assignment in extended slicing as well.

a = [1,2,3,4,5,6,7,8,9]
a[1:6:2] = [0,0,0]
print(a)
>>> [1, 0, 3, 0, 5, 0, 7, 8, 9]

But assignment in list with extended slice works only if the size of the sequence is equal to size of the slice. Extended Slice Assignment provides similar function to Tuple Unpacking.

a = [1,2,3,4,5,6,7]
a[1:6:2] = [0,0]
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
ValueError: attempt to assign sequence of size 2 to extended slice of size 3

It goes without saying that slice assignment does not work because strings are immutable.

Slicing with negative step

Step values in the slice can take negative values with indexes in the slice are in decreasing order. So, a[3:1:-1] prints [3,2] while a[1:3:-1] prints empty list because you are starting at 1, and trying to count backwards to 3.

In python each element in the list is also assigned a negative index which is equal to index minus the length of the list. This negative indexes can also be used in slicing.

>>> a[-3:-1]
[6, 7]
>>> a[-1:-3]
[]

This is a useful in lot of ways but can lead to bugs if you do not use your indexes properly in while/for loop.

Hopefully this article makes this clear when it comes to slicing. Please like this post if you like it. Any comments/suggestions are welcome.