[Python-ideas] PEP 532: A circuit breaking operator and protocol
Kyle Lahnakoski
klahnakoski at mozilla.com
Mon Nov 14 21:57:39 EST 2016
It would be nice if
....coalesce(EXPR1, EXPR2, EXPR3)
Evaluated the N+1 argument only if the Nth evaluated to None. Of course
this may break the general patterns in the Python language. Maybe we can
fake it by wrapping the expressions in lambdas:
....coalesce(lambda: EXPR1(), lambda EXPR2(), lambda EXPR3())
and defining a `coalesce` as
def coalesce(*args):
....for a in args:
........a_val=a()
........if a_val is not None:
............return a_val
....return None
Making a coalesce call looks painful, but allowing the called function
to control the evaluation of its parameters may be useful. Suppose we
can pass methods to functions; using generators to do so: Let & refer to
lazy-evaluated parameters:
....def coalesce(&a, &b):
........if a is None:
............return b
........else:
............return a
....
....c = coalesce(expr1(), expr2())
Would be converted to :
....def coalesce(a, b):
........a = yield
........a_val = a()
........if a_val is None:
............b = yield
............b_val = b()
............return b_val
........else:
............return a_val
....
....exprs = [expr1, expr2]
....temp = coalesce()
....for e in exprs:
........try:
............c = temp.next(e)
........except StopIteration:
............break
Or, even better...
....def coalesce(*&args):
........for a_val in args:
............if a_val is not None:
................return a_val
........return None
....
....c = coalesce(expr1(), expr2())
Gets converted to
....def coalesce(*args):
........for a in args:
............a_val = a()
............if a_val is not None:
................return a_val
........return None
....
....exprs = [expr1, expr2]
....temp = coalesce()
....for e in exprs:
........try:
............c = temp.next(e)
........except StopIteration:
............break
...or something like that. I can not think of other reasons for this
type of expansion; maybe logical `and` can be given a magic method:
"__logand__":
....def __logand__(self, &other):
........if self:
............return True
........return o
....
....c = my_object and some_other()
which has a combination of immediately-evaluated parameters, and
lazy-evaluated parameters:
class MyClass(object):
....def __logand__(self):
........if self:
............yield True
............return
........other = yield
........return other()
....
....exprs = [some_other]
....temp = MyClass.__logand__(my_object)
....for e in exprs:
........try:
............c = temp.next(e)
........except StopIteration:
............break
I hope that the acrobatics shown here might be easier to implement at a
lower level; where in-line generator code collapses to simple branched
logic.
On 11/13/2016 1:51 AM, Nick Coghlan wrote:
>
> At that point, if we did decide to offer a builtin instead of
> dedicated syntax, the option I'd argue for is actually SQL's
> "coalesce": coalesce(EXPR1) else coalesce(EXPR2) else EXPR3 Yes, it's
> computer science jargon, but the operation itself is an odd one that
> doesn't really have an established mathematical precedent or
> grammatical English equivalent. Cheers, Nick.
More information about the Python-ideas
mailing list