Sorry to reply this way. I saw this on google, but neither this nor my previous post has shown up yet on my news server. Wonder what all this delay is lately ;-/
>From: Paul Rubin <http://[EMAIL PROTECTED]> >Subject: Re: Augmented generators? >Date: 10 Jan 2006 11:03:39 -0800 >Message-ID: <[EMAIL PROTECTED]> >"Andrew Koenig" <[EMAIL PROTECTED]> writes: >> Can anyone think of an easy technique for creating an object that acts like >> a generator but has additional methods? >> For example, it might be nice to be able to iterate through an associative >> container without having to index it for each element. >Normally you'd define a class and give it __iter__ and next operations. >I guess that can get messy. Does it qualify as easy for your purposes? >> Of course I can write such a beast as a class, but that prevents me from >> taking advantage of the yield statement in its implementation. >You can make an internal function that's a generator with a yield >statement (or a generator expression instead of a function, if simple >enough). The class's 'next' method would loop through the generator >and return each value from it. >Let me try your example: This suffers from the same problem as my first go (an exhausted iterator is not supposed to restart). >>> class kviter: ... def __init__(self, d): ... self.d = d ... def __iter__(self): ... def iter1(d, s=self): ... for k in d: ... # lambda not really needed here, but you wanted value to ... # be callable instead of just an attribute ... s.value = (lambda r=d[k]: r) ... yield k ... return iter1(self.d) ... Using my example with your iterator: >>> it = kviter(dict(enumerate('abcd'))) >>> for i in it: ... if i%2: print i, it.value() ... 1 b 3 d Ok, but this shouldn't happen at this point: >>> for i in it: ... if i%2: print i, it.value() ... 1 b 3 d Whereas, >>> class augiter(object): ... def __init__(self, d): ... self._it = self._gen(d) ... def __iter__(self): return self ... def _gen(self, d): ... for k, self._v in d.items(): yield k ... def next(self): return self._it.next() ... def value(self): return self._v ... >>> it = augiter(dict(enumerate('abcd'))) >>> for i in it: ... if i%2: print i, it.value() ... 1 b 3 d >>> for i in it: ... if i%2: print i, it.value() ... >>> Letting __init__ create the generator instance by calling a bound method coded with yield makes integrating the latter style pretty easy, even though you still need __iter__ and next methods. Hm, you could factor that out into a base class though: (then you just need the convention that a derived class must define at least the _gen method. Then augment to taste) >>> class AugiterBase(object): ... def __init__(self, *args, **kw): ... self._it = self._gen(*args, **kw) ... def __iter__(self): return self ... def next(self): return self._it.next() ... >>> class DervAugit(AugiterBase): ... def _gen(self, d): ... for k, self._v in d.items(): yield k ... def value(self): return self._v ... >>> it = DervAugit(dict(enumerate('abcd'))) >>> for i in it: ... if i%2: print i, it.value() ... 1 b 3 d >>> for i in it: ... print i, it.value() ... >>> it = DervAugit(dict(enumerate('abcd'))) >>> for i in it: ... print i, it.value() ... 0 a 1 b 2 c 3 d Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list