[Python-ideas] Another way to avoid clumsy lambdas, while adding new functionality
Steven D'Aprano
steve at pearwood.info
Wed Mar 5 12:18:23 CET 2014
On Tue, Mar 04, 2014 at 11:09:02PM +0000, Carl Smith wrote:
> The tentatively proposed idea here is using dollar signed expressions to
> define 'bills'. A bill object is essentially an expression which can be
> evaluated any number of times, potentially in different scopes.
Please don't invent "cute" names for things which already have names.
What you are describing could be considered a thunk, or a macro, or a
lazily-evaluated expression, depending on the precise details of how it
works. But calling it a "bill" just because it starts with a $ just
makes me cringe.
> The following expression [a bill literal] would be pointless, but would
> define a bill that always evaluates to 1.
>
> $1
>
> So, eval($1)==1.
My personal feeling here is that if you have to explicitly call eval on
the "bill" to evaluate it, it's not worth doing. If we were happy with
that, we've already got compile(), or we have functions. Or just eval a
string directly. My feeling is that evaluating the expression needs to
be implicit, performed at need rather than up front, rather in the same
way that short-circuiting operators don't actually evaluate the
expression unless needed:
x or expr # expr is only evaluated if x is a falsey value
Yes, I know, the Zen of Python says that "explicit is better than
implicit", but the Zen is intended as guidelines, not thought-blockers.
We have perfectly good explicit idioms for delaying computations (eval
and functions), to make the thunk/macro/whatever worth doing it has to
offer something different.
> Some better examples...
>
> * assign a bill to `a` so that `a` will evaluate to the value of the name
> `foo` any time that `a` is evaluated, in the scope of that evaluation
>
> a = $foo
>
> * as above, but always plus one
>
> a = $foo + 1
>
> * make `a` a bill that evaluates to the value of the name `foo` at the time
> that `a` is evaluated, in that scope, plus the value of `bar` **at the time
> and in the scope of the assignment to `a`**
>
> a = $foo + bar
Hmmm. That implies that if you want an entire expression to have
delayed evaluation, you have to tag everything with a sigil:
a = $spam + $eggs - $spam*$eggs + $cheese*$spam
I think it is better to have syntax with delimiters, to turn delayed
evaluation ON and OFF, rather than having to tag each and every
sub-expression:
a = `spam + eggs - spam*eggs + cheese*spam`
(disclaimer: using ` ` is just for the sake of illustration.)
> Note. Similarly to mixing floats with ints, any expression that contains a
> bill evaluates to a bill, so if `a` is a bill, `b=a+1` makes `b` a bill
> too. Passing a bill to eval should be the obvious way to get the value.
>
> The point? It allows functions to accept bills to use internally. The
> function would specify any names the bill can reference in the function's
> API, like keywords.
Well, this contradicts your previous point. If any expression that
contains a "bill" is a "bill", then so is func(bill). So given that,
your example here:
> def f(b): # the bill arg `b` can reference `item`
> for item in something:
> if eval(b): return True
>
> f($item < 0)
would actually need to be written as:
eval(f($item < 0))
--
Steven
More information about the Python-ideas
mailing list