Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

itertools.cycle(iterable) vs while True

I was recently asked to do this task (school) :

Write a loop generator, which takes as parameter a finite iterable, and generates in infinite loop the iterable

So I did :

import itertools
def loop(l):
    for eleme‍‌​‍‌nt in itertools.cycle(l):
        yield element

and one of my classmate did :

def loop(l):
    while True:
​‍         for element in l:
            yield element

I'd like to know what are the main differences between the two and if there is a more "pythonic" way to write something simple as this.

like image 656
L. Faros Avatar asked Sep 06 '18 19:09

L. Faros


People also ask

How does Itertools cycle work?

cycle() Iterator is defined as object types which contains values that can be accessed or iterated using a loop. There are different iterators that come built-in with Python such as lists, sets, etc. Itertools is the Python module that contains some inbuilt functions for generating sequences using iterators.

Is Itertools faster than for loops?

That being said, the iterators from itertools are often significantly faster than regular iteration from a standard Python for loop.

What is Islice?

islice() - The islice() function allows the user to loop through an iterable with a start and stop , and returns a generator. map() - The map() function creates an iterable map object that applies a specified transformation to every element in a chosen iterable.

How does Itertools combinations work?

combinations() provides us with all the possible tuples a sequence or set of numbers or letters used in the iterator and the elements are assumed to be unique on the basis of there positions which are distinct for all elements. All these combinations are emitted in lexicographical order.


3 Answers

I'd like to know what are the main differences between the two ...

The main difference is that these code snippets are not entirely equivalent in behaviour. Using cycle, you can accept and repeat an exhaustible iterator, whereas the while loop can not.

>>> def gen():
...     yield 1
...     yield 2
...     
>>> def loop_it(it):
...     for element in itertools.cycle(it):
...         yield element
...         
>>> g = loop_it(gen())
>>> next(g)
1
>>> next(g)
2
>>> next(g)
1

Contrast:

>>> def loop_while(it):
...     while True:
...         for element in it:
...             yield element
...             
>>> g = loop_while(gen())
>>> next(g)
1
>>> next(g)
2
>>> next(g)
# ... hangs forever

... and if there is a more "pythonic" way to write something simple as this

My recommendation is for the while loop, exactly as written. If you are asked in a school task to write the generator, it will likely be frowned upon to use "one prepared earlier" from itertools. The while loop is also more Pythonic. An "itertoolsthonic" approach would instead be using the cycle directly, like this:

items = itertools.cycle(l)
# do something with `items`

There is no point to write the extra scaffolding of a generator function and for loop yielding from an itertools.cycle - since the cycle is already an iterator, you would just use it directly.

like image 101
wim Avatar answered Oct 22 '22 12:10

wim


You're right, itertools.cycle isn't of great interest here over the classical while True loop.

On the other hand, it's of great help in infinite generator comprehensions, where you cannot create an infinite loop because it only allows for, tests and function calls. Example to generate squared value of a list indefinitely:

generator = (x*x for x in itertools.cycle(l))

Of course you could always shorten your current code with:

def loop(l):
    yield from itertools.cycle(l)

or even:

loop = itertools.cycle
like image 33
Jean-François Fabre Avatar answered Oct 22 '22 10:10

Jean-François Fabre


As I see it, the purpose of itertools.cycle is that you wouldn't have to write it yourself at all :)

The most pythonic way would be to simply write loop = itertools.cycle.

If you truly need to write it as a generator for your school assignment, the second form would probably perform faster, because the first form basically does the same but also has additional overhead from re-yielding the values from cycle in your generator.

like image 23
Mikhail Burshteyn Avatar answered Oct 22 '22 10:10

Mikhail Burshteyn