Welcome, guest | Sign In | My Account | Store | Cart

This class allows you to use generators as more list-like streams. The chief advantage is that it is impossible to iterate through a generator more than once, while a stream can be re-used like a list.

Python, 35 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class _stream_iter:
    def __init__(self, s):
        self.stream = s
        self.i = 0
    def next(self):
        try:
            val = self.stream[self.i]
        except IndexError: raise StopIteration
        self.i += 1
        return val

class stream(list):
    def __init__(self, iterator):
        list.__init__(self)
        self.it = iterator
        self.length = 0
        self.done = 0
    def __iter__(self):
        return _stream_iter(self)
    def __getitem__(self, i):
        if i >= self.length or self.length == 0:
            for j in range(i + 1 - self.length):
                self.append(self.it.next())
            self.length = i+1
        elif i < 0:
            for i in self.it:
                self.append(i)
            self.length = self.__len__()
        return list.__getitem__(self, i)
    def __getslice__(self, i, j):
        junk, junk = self[i], self[j]
        return list.__getslice__(self, i, j)
    def __repr__(self):
        return '<stream instance at 0x%x, %r materialized>' \
               % (id(self), list.__repr__(self))
                

The chief application of a stream is cases where you have a generator you want to iterate through more than once. With just a generator, that is difficult:

>>> def upto(n):
    for i in range(n):
        yield i




>>> to5 = upto(5)
>>> for i in to5:
    if i == 3: break
    print i,

0 1 2

>>> for i in to5:
    print i,

4

The generator is stateful, so you can only iterate through it once. If you break off in the middle of a loop, the next call to its next() method will pick up from where it left off. With a stream, this is not the case:

>>> to5stream = genlib.stream(upto(5))
>>> for i in to5stream:
    if i == 3: break
    print i,

0 1 2

>>> for i in to5stream:
    print i,

0 1 2 3 4

>

The benefits of a generator are mostly preserved: the whole list result isn't materialized at once, but what is materialized is still stored.

Created by Ben Wolfson on Wed, 5 Jun 2002 (PSF)
Python recipes (4591)
Ben Wolfson's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks