40

It's my understanding that using a Generator is the best way to achieve something like this, but I'm open to suggestions.

Specifically, one use case is this: I'd like to print some items alongside another list, of an arbitrary length, truncating the initial iterator as necessary.

Here is working python code that demonstrates the exact example behavior I desire:

    def loop_list(iterable):
        """
        Return a Generator that will infinitely repeat the given iterable.

        >>> l = loop_list(['sam', 'max'])
        >>> for i in range(1, 11):
        ...     print i, l.next()
        ... 
        1 sam
        2 max
        3 sam
        4 max
        5 sam
        6 max
        7 sam
        8 max
        9 sam
        10 max

        >>> l = loop_list(['sam', 'max'])
        >>> for i in range(1, 2):
        ...     print i, l.next()
        ... 
        1 sam
        """
        iterable = tuple(iterable)
        l = len(iterable)
        num = 0
        while num < l:
            yield iterable[num]
            num += 1
            if num >= l:
                num = 0

The Problem / My Question

As you may have noticed, this only works on lists/tuples/iterables that implement __getitem__ (if I'm not mistaken). Ideally, I'd like to be able to pass any iterable, and receive a generator that can properly loop over it's content.

If there's a better way to do something like this without a generator, I'm fine with that as well.

anonymous coward
  • 12,594
  • 13
  • 55
  • 97
  • Neither of those examples represent an infinite loop, I'm confused as to what you're asking. – Arafangion Oct 17 '12 at 23:24
  • The outer loop is not infinite, but the generator will continue to list its items indefinitely. – anonymous coward Oct 17 '12 at 23:25
  • Then go with Hans' response, however as an exercise, I would suggest you consider how to implement it yourself. – Arafangion Oct 17 '12 at 23:28
  • I'm curious about the "Equivalent to" code and related Note about memory consumption. The way I'm reading it, would `saved` continue to grow as long as the generator is accessed/`.next()` is called? **UPDATE**: Testing says no, so obviously I'm not good at reading generator code. =/ Have some learnin' to do. – anonymous coward Oct 17 '12 at 23:33
  • No. In the source provided in the documentation, `saved` is built once (on the first time through the iterable) and then only read from then on. – Jon Gauthier Oct 17 '12 at 23:38

4 Answers4

103

You can use itertools.cycle (source included on linked page).

import itertools

a = [1, 2, 3]

for element in itertools.cycle(a):
    print element

# -> 1 2 3 1 2 3 1 2 3 1 2 3 ...
Jon Gauthier
  • 25,202
  • 6
  • 63
  • 69
  • 1
    `Note, this member of the toolkit may require significant auxiliary storage (depending on the length of the iterable).` – allenyllee May 12 '20 at 04:06
10

Try this-

L = [10,20,30,40]

def gentr_fn(alist):
    while 1:
        for j in alist:
            yield j

a = gentr_fn(L)
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()
print a.next()

>>gentr_fn(x,y)
10 20 30 40 10 20 30 ...
Aby
  • 121
  • 1
  • 4
2

You can use module to keep it simple. Just make sure not to start iterating from 0.


my_list = ['sam', 'max']

for i in range(1, 100):
    print(my_list[(i % len(my_list))-1])


avi_k
  • 21
  • 1
  • You can start the range at `0`, easily, by simply using `for i in range(0, 100): print(my_list[i % len(my_list)])` but in any case this will only iterate 100 times, the op wants to keep cycling indeterminately. – juanpa.arrivillaga Dec 01 '21 at 01:19
-7

You can iterate over a list, appending an item to it:

somelist = [item1, item2, item3]
for item in somelist:
    somelist.append(item)
    do_something()