[Python-ideas] [Python-Dev] minmax() function returning (minimum, maximum) tuple of a sequence

Jacob Holm jh at improva.dk
Mon Oct 25 12:19:14 CEST 2010


On 2010-10-25 04:37, Guido van Rossum wrote:
> This should not require threads.
> 
> Here's a bare-bones sketch using generators:
> 

If you don't care about allowing the funcs to raise StopIteration, this
can actually be simplified to:


def reduce_collector(func):
    try:
        outcome = yield
    except GeneratorExit:
        outcome = None
    else:
        while True:
            try:
                val = yield
            except GeneratorExit:
                break
            outcome = func(outcome, val)
    raise StopIteration(outcome)

def parallel_reduce(iterable, funcs):
    collectors = [reduce_collector(func) for func in funcs]
    values = [None for _ in collectors]
    for coll in collectors:
        next(coll)
    for val in iterable:
        for coll in collectors:
            coll.send(val)
    for i, coll in enumerate(collectors):
        try:
            coll.throw(GeneratorExit)
        except StopIteration as err:
            values[i] = err.args[0]
    return values


More interesting (to me at least) is that this is an excellent example
of why I would like to see a version of PEP380 where "close" on a
generator can return a value (AFAICT the version of PEP380 on
http://www.python.org/dev/peps/pep-0380 is not up-to-date and does not
mention this possibility, or even link to the heated discussion we had
on python-ideas around march/april 2009).

Assuming that "close" on a reduce_collector generator instance returns
the value of the StopIteration raised by the "return" statements, we can
simplify the code even further:


def reduce_collector(func):
    try:
        outcome = yield
    except GeneratorExit:
        return None
    while True:
        try:
            val = yield
        except GeneratorExit:
            return outcome
        outcome = func(outcome, val)

def parallel_reduce(iterable, funcs):
    collectors = [reduce_collector(func) for func in funcs]
    for coll in collectors:
        next(coll)
    for val in iterable:
        for coll in collectors:
            coll.send(val)
    return [coll.close() for coll in collectors]


Yes, this is only saving a few lines, but I find it *much* more readable...



- Jacob




More information about the Python-ideas mailing list