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.
Return type
Itertools islice method returns an iterator which returns the individual values on iterating or traversing over.
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.
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.
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.
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="")
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)
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)
FAQ’s on itertools.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.
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.
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.