[Python-ideas] One more time... lambda function <--- from *** signature def.

Chris Angelico rosuav at gmail.com
Tue Mar 4 13:07:46 CET 2014


On Tue, Mar 4, 2014 at 10:09 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> Agreed. What I have in my head is some vague concept that the Python
> evaluation rules will somehow know when to evaluate the thunk and when
> to treat it as an object, which is (as I understand it) what happens in
> Algol. Again, just thinking aloud, perhaps we do this:
>
> thunk = `some_expression`  # delays evaluation
> a = [0, 1 + thunk]  # evaluates thunk in the current scope
> b = [0, `1 + thunk`]  # delays evaluation and creates a thunk object
>                       # equivalent to `1 + some_expression`
> c = b[1]  # now evaluates the thunk object
> d = f(2, thunk)  # evaluates thunk in f's scope
> e = g(3, `thunk`)  # passes the un-evaluated thunk object to g
>
> Consider this just a sketch, and in no way fully thought out.
>
> (This will most definitely need a PEP.)

PEP can come later. First, let's get some solid use-cases, and start
looking at implications. The way it's described here, there's
effectively magic when you try to look at an object of this type,
which will break a lot of assumptions. Most people expect that:

foo = bar
assert foo is bar

to be a safe assumption, but if bar is a thunk, then it's getting
evaluated separately in each of those, and that's potentially going to
create different objects and/or even have side effects. That's going
to surprise people. On the flip side, that's something that could be
dealt with with a naming convention for thunks. We have _private,
__mangled, __magic__, anticollision_, CONSTANT, Class... maybe we
could have thunk__ or something. It's most confusable with magic and
anticollision, but since both of those are connected with specific
keywords, it's reasonably likely there'll be no actual confusion.

Specific downside: There's no way to actually pass an unevaluated
thunk around. Technically, `thunk__` will create a new wrapper thunk
and pass that along. That'll often have the same effect, but it won't
be quite identical (same as there's a difference between f(g) and
f(lambda x: g(x)) in that the second one lazily looks up g), so that
might cause confusion. But you could always special-case it: writing
`thunk__` will be guaranteed to transmit the thunk unchanged, and if
you actually mean to add another wrapper layer, use `(thunk__)` or
something instead.

The biggest thing to figure out is scoping. Does a thunk take a
snapshot of its enclosing scope (a closure), or is it an expression
that gets evaluated in the target namespace? The latter could be
extremely confusing, but the former's just what a nested function
does, so this'd just be a new lambda syntax.

Python's existing lambda syntax has its flaws and its detractors, but
it has one huge benefit over thunking: It exists. :) Thunking has to
get over that difference. I'd like to see some proposals.

ChrisA


More information about the Python-ideas mailing list