genexp reduce syntax in 2.5a1

Boris Borcic bborcic at gmail.com
Tue Apr 18 07:47:43 EDT 2006


On the python3000 mailing list there was some discussion of a "comprehension 
syntax" for reduce.

This inspired me the following proof-of-concept in pure python 2.5a1, although I 
don't know if it relies on an intended feature or a(n unintended) bug.

Cheers, BB
--

def ireduce(gen) :
     """
     Generator expression syntax for reduce and generalizations

     Usage examples:

     - (yield) nothing as below if there is no seed value
     *and* the expression consists of a single arithmetic op

     >>> ireduce(x+(yield) for x in range(101)) # famous Gauss example
     5050
     >>> ireduce(x*(yield) for x in range(1,6))
     120

     - if there is a seed, yield it (unless it's None)

     >>> ireduce(x*(yield 2) for x in range(1,6)) # 2*1*2*3*4*5
     240
     >>> ireduce(x*(yield 2) for x in range(2,6)) # 2*2*3*4*5
     240
     >>> ireduce(x*(yield 2) for x in range(6))   # 2*0*1*2*3*4*5
     0

     - if the seed is None, (yield INone) instead

     >>> ireduce((x,(yield INone)) for x in "for all good men".split())
     ('men', ('good', ('all', ('for', None))))

     >>> ireduce([(yield INone),x] for x in "for all good men".split())
     [[[[None, 'for'], 'all'], 'good'], 'men']

     - do as below if you want no special seed and the operation to reduce
     isn't a simple arithmetic operation

     >>> ireduce((x,(yield Seed(x))) for x in "for all good men".split())
     ('men', ('good', ('all', 'for')))

     >>> ireduce(x+' '+(yield Seed(x)) for x in "for all good men".split())
     'men good all for'

     >>> ireduce({ x : (yield Seed(x))} for x in "for all good men".split())
     {'men': {'good': {'all': 'for'}}}

     - and notice these for a comparison

     >>> ireduce({ x : (yield x)} for x in "for all good men".split())
     {'men': {'good': {'all': {'for': 'for'}}}}

     >>> ireduce({ x : (yield Seed(None))} for x in "for all good men".split())
     {'men': {'good': {'all': None}}}
     """

     cumulate = gen.next()
     if cumulate is None :
         cumulate = Neutral()
     elif cumulate is INone :
         cumulate = None
     elif isinstance(cumulate,Seed) :
         cumulate = cumulate.seed
         gen.send(cumulate)
         gen.next()
     try :
         while True :
             cumulate = gen.send(cumulate)
             gen.next()
     except StopIteration :
         return cumulate

class Neutral :
     def __coerce__(self,other) :
         self.other = other
         return (self,self)

     def __getattr__(self,attr) :
         return lambda *x,**y : self.__dict__['other']

class INone : pass

class Seed :
     def __init__(self,seed) :
         self.seed = seed



More information about the Python-list mailing list