Iterator class to allow self-restarting generator expressions?

Lie Ryan lie.1296 at gmail.com
Mon Mar 2 09:48:02 CET 2009


Gabriel Genellina wrote:
> En Sun, 01 Mar 2009 15:51:07 -0200, Chris Rebert <clp2 at rebertia.com>
> escribió:
>> On Sun, Mar 1, 2009 at 8:54 AM, Gabriel Genellina
>> <gagsl-py2 at yahoo.com.ar> wrote:
>>> En Sun, 01 Mar 2009 13:20:28 -0200, John O'Hagan
>>> <research at johnohagan.com>
>>> escribió:
>>>
>>>> Inspired by some recent threads here about using classes to extend the
>>>> behaviour of iterators, I'm trying to replace some some top-level
>>>> functions
>>>> aimed at doing such things with a class.
> 
>>> I'm afraid you can't do that. There is no way of "cloning" a generator:
>>
>> Really? What about itertools.tee()? Sounds like it'd do the job,
>> albeit with some caveats.
>> http://docs.python.org/library/itertools.html#itertools.tee
> 
> It doesn't clone the generator, it just stores the generated objects in
> a temporary array to be re-yielded later.
> 

How about creating something like itertools.tee() that will save and
dump items as necessary. The "new tee" (let's call it tea) would return
several generators that all will refer to a common "tea" object. The
common tea object will keep track of which items has been collected by
each generators and generate new items as necessary. If an item has
already been collected by all generators, that item will be dumped.

Somewhat like this: # untested

class Tea(object):
    def __init__(self, iterable, nusers):
        self.iterable = iterable
        self.cache = {}
        self.nusers = nusers

    def next(self, n):
        try:
            item, nusers = self.cache[n]
            self.cache[n] = (item, nusers - 1)
        except IndexError: # the item hasn't been generated
            item = self.iterable.next()
            self.cache[n] = (item, nusers)
        else:
            if nusers == 0:
                del self.cache[n]
            return item

class TeaClient(object):
    def __init__(self, tea):
        self.n = 0
        self.tea = tea
    def next(self):
        self.n += 1
        return self.tea.next(self.n)

def tea(iterable, nusers):
    teaobj = Tea(iterable, nusers)
    return [TeaClient(teaobj) for _ in range(nusers)]




More information about the Python-list mailing list