Iterator addition

Tom Anderson twic at urchin.earth.li
Sat Nov 12 19:21:56 EST 2005


On Thu, 9 Nov 2005, it was written:

> aleax at mail.comcast.net (Alex Martelli) writes:
>
>>> Is there a good reason to not define iter1+iter2 to be the same as
>>
>> If you mean for *ALL* built-in types, such as generators, lists, files,
>> dicts, etc, etc -- I'm not so sure.
>
> Hmm, there might also be __add__ operations on the objects, that would 
> have to take precedence over iterator addition.  Iterator addition 
> itself would have to be a special kludge like figuring out "<" from 
> __cmp__, etc.
>
> Yeah, I guess the idea doesn't work out that well.  Oh well.

How about if we had some sort of special sort of iterator which did the 
right thing when things were added to it? like an iterable version of The 
Blob:

class blob(object):
 	def __init__(self, it=None):
 		self.its = []
 		if (it != None):
 			self.its.append(iter(it))
 	def __iter__(self):
 		return self
 	def next(self):
 		try:
 			return self.its[0].next()
 		except StopIteration:
 			# current iterator has run out!
 			self.its.pop(0)
 			return self.next()
 		except IndexError:
 			# no more iterators
 			raise StopIteration
 	def __add__(self, it):
 		self.its.append(iter(it))
 		return self
 	def __radd__(self, it):
 		self.its.insert(0, iter(it))

Then we could do:

all_lines = blob(file1) + file2 + file3
candidate_primes = blob((2,)) + (1+2*i for i in itertools.count(1))

Which, although not quite as neat, isn't entirely awful.

Another option would be a new operator for chaining - let's use $, since 
that looks like the chain on the fouled anchor symbol used by navies etc:

http://www.diggerhistory.info/images/badges-asstd/female-rels-navy.jpg

Saying "a $ b" would be equivalent to "chain(a, b)", where chain (which 
could even be a builtin if you like) is defined:

def chain(a, b):
 	if (hasattr(a, "__chain__")):
 		return a.__chain__(b)
 	elif (hasattr(b, "__rchain__")): # optional
 		return b.__rchain__(a)
 	else:
 		return itertools.chain(a, b) # or equivalent

Whatever it is that itertools.chain or whatever returns would be modified 
to have a __chain__ method which behaved like blob.__add__ above. This 
then gets you:

all_lines = file1 $ file2 $ file3
candidate_primes = (2,) $ (1+2*i for i in itertools.count(1))

And we're halfway to looking like perl already! Perhaps a more pythonic 
thing would be to define a "then" operator:

all_lines = file1 then file2 then file3
candidate_primes = (2,) then (1+2*i for i in itertools.count(1))

That looks quite nice. The special method would be __then__, of course.

tom

-- 
if you can't beat them, build them



More information about the Python-list mailing list