[Python-Dev] product()

Alex Martelli aleaxit at yahoo.com
Sat Oct 25 19:04:18 EDT 2003


On Saturday 25 October 2003 11:14 pm, Guido van Rossum wrote:
> > it might be "alltrue" and "anytrue" -- the short-circuiting ones,
> > returning the first true or false item found respectively, as in:
> >
> > def alltrue(seq):
> >     for x in seq:
> >         if not x: return x
> >     else:
> >         return True
> >
> > def anytrue(seq):
> >     for x in seq:
> >         if x: return x
> >     else:
> >         return False
> >
> > these seem MUCH more generally useful than 'product' (but,
> > I still opine, not quite enough to warrant being built-ins).
>
> These are close to what ABC does with quantifiers.  There, you can
> write
>
>   IF EACH x IN sequence HAS x > 0: ...
>
> ABC has the additional quirk that if there's an ELSE branch, you can
> use x in it (as a "counter-example").
>
> In Python, you could write this as
>
>   if alltrue(x > 0 for x in sequence): ...
>
> but the current design doesn't expose x to the else branch.

Right -- it would return the condition being tested, x>0, when non-true,
so just a False; there is no natural way for it to get the underlying
object on which it's testing it.  This is somewhat the same problem as
Peter Norvig's original Top(10) accumulator example: if you just pass to
it the iterator of the comparison keys, it can't collect the 10 items with
the highest comparison keys.

Maybe
    alltrue(sequence, pred=lambda x: x>0)
might be better (pred would default to None meaning to test the items
in the first argument, the iterator, for true/false directly):

def alltrue(seq, pred=None):
    if pred is None:
        def pred(x): return x
        def wrap(x): return x
    else:
        class wrap(object):
            def __init__(self, x): self.counterexample = x
            def __nonzero__(self): return False
    for x in seq:
        if not pred(x): return wrap(x)
    else:
        return True

or something like that (I do think we need the wrap class, so that
alltrue can return an object that evaluates to false but still allows
the underlying "counter-example" to be retrieved if needed).

Use, of course, would have to be something like:

allpositives = alltrue(sequence, pred=lambda x: x>0)
if allpositives: print "wow, all positives!"
else: print "nope, some nonpositives, e.g.", allpositives.counterexample

Unfortunately, this usage is pushing at TWO not-strengths of Python:
no neat way to pass an unnamed predicate (lambda ain't really all
that neat...) AND no assignment-as-expression.  So, I don't think it
would really catch on all that much.


Alex




More information about the Python-Dev mailing list