Python’s itertools.islice() | Slicing for Iterators?

Did you know even iterators can be sliced! Itertools module of Python provides an excellent function itertools.islice() to achieve this task. It handles iterators in a memory-efficient way, preventing unnecessary load on our machines.

Itertools.islice()

If you are familiar with Python, then there is a perfect chance of you coming across the term slicing. Slicing slices or segments in a sequence(in the case of Python – lists, tuples, string, range) returns a slice object but in the case of the itertools.islice() method; an iterator is returned.

Although there are many other valuable functions in the itertools library, in this section, we will be focussing on all the aspects of the islice method; however, you can get a glimpse of other methods from here.

Import

# can be used as itertools.islice()
import itertools 

# or you can use it as .islice()
from itertools import islice

Syntax & Parameters

Syntax:

itertools.islice(iterable, start, stop, step)

Parameters:

  • Iterable – iterable are objects which generate an iterator. For instance, common python iterable are list, tuple, string, dictionaries
  • Start – start value defines the starting position to begin slicing from, it can be a natural number i.e. 0,1,2,3…
  • Stop – stop value defines the ending position, it slices until the number specified(not including) and can be natural number.
  • Step – step defines the jump or the incrementation in the value.

Note: While in the case of the slice method; the start, stop and step value can be negative but this is not valid for the islice method, it returns a ValueError.

Value error islice method
The error generated on passing negative values to the islice method

Return type

Itertools islice method returns an iterator which returns the individual values on iterating or traversing over.

return type of islice() method o itertools
Return type of itertools.islice()

Complexity

Itertools islice method over a list using an iterator and avoids memory usage.

Working of itertools.islice()

Example 1: Single value passed along with iterable acts as the stop parameter.

import islice itertools

ite = itertools.islice(range(10), 7)
for item in ite:
    print(item)

In the example code above, we passed a range of numbers from 0 to 10 and passed a single additional parameter 7, which serves as the stop parameter. Hence, we get values from 0 to 6.

itertools.islice() example 1 image
The output of example 1

Example 2: With start and stop values

import itertools

ite = itertools.islice(range(10), 1, 6)
for item in ite:
    print(item)

In the example code above, we passed a range of numbers from 0 to 10 and passed two parameters, 1 and 6, which are the start and stop values, respectively. Hence, we get values from 1 to 5.

itertools.islice() example 2 image
The output of example 2

Example 3: With a step value

from itertools import islice

ite = islice(range(10), 1, 9, 3)
for item in ite:
    print(item)

In the example code above, we passed a range of numbers from 0 to 10 and passed three more parameters, 1, 9, and 3, which are the start, stop, and step values, respectively. Hence, we get values from 1 to 7 with a step of 3.

itertools.islice() example 3 image
The output of example 3

Real-world use-case of islice

It is very similar to the regular slicing method. However regular slice() method creates a copy of the original sequence(list, tuple, string, etc.). This will take up a significant amount of computer memory if the original sequence is too large.

On the contrary, islice returns an iterable, and therefore it is faster since elements can be generated on the fly. In other words, each data item will be generated when the iterated is called upon.

Suppose you are working on a real-world project. It has thousands of lines of code and log files. An error has occurred on some specific lines. Will you load the entire log file’s iterator into the memory to debug the error? Definitely not. You can only get those lines where the expected error might be present.

import itertools

with open('test.log','r') as file:
	header = itertools.islice(file,5)
	for line in header:
		print(line,end="")
log files output islice()
Example log file line to find an error

islice to list

One can very quickly convert iterator by using the list() function.

sliced = itertools.islice(range(100), 1, 101, 3)
sliced_to_list = list(sliced)
print(sliced_to_list)
islice() iterator to list example 1
islice() generated iterator to list using list() function

Another interesting way to replicate the above example is to use the * operator to unpack the values:

sliced = itertools.islice(range(100), 1, 101, 4)
sliced_to_list = [*sliced]
print(sliced_to_list)
islice() iterator to list example 2
islice() generated iterator to list using * operator

FAQ’s on itertools.islice()

What’s the difference between slice vs. islice?

The slice creates a slice object which occupies memory. At the same time, the islice() method iterates over a list using an iterator and avoids memory usage as the elements are generated on the fly.

Are there any performance issues with itertools.islice()?

Iterators add an iteration speed overhead. They generally are not faster. In contrast, average slicing speed is much quicker than the islice method(only if you aren’t storing the slice into a new list) because the list type has direct access to the internal storage for a list object.

How to fix itertools.slice() object is not subscriptable?

itertools islice method returns a itertools.islice object, which doesn’t support indexing.
# Try using a for loop to iterate over
for slice in itertools.islice(range(10),6):
print(slice)

Conclusion

Thus, if memory efficiency plays a role, the islice method is the way to go. The only caveat is that it doesn’t support negative indexing as it iterates the iterable from start to end.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments