[Python-ideas] A "local" pseudo-function
Tim Peters
tim.peters at gmail.com
Mon Apr 30 12:18:17 EDT 2018
[Tim, on differences among Scheme-ish `let`, `let*`, `letrec` binding]
> ...
>
> You can play, if you like, with trying to define the `iseven` lambda
> here in one line by nesting lambdas to define `even` and `odd` as
> default arguments:
>
> even = (lambda n: n == 0 or odd(n-1))
> odd = (lambda n: False if n == 0 else even(n-1))
> iseven = lambda n: even(n)
>
> Scheme supplies `letrec` for when "mutually recursive" bindings are
> needed. In Python that distinction isn't nearly as evidently needed,
> because Python's idea of closures doesn't capture all the bindings
> currently in effect,. For example, when `odd` above is defined,
> Python has no idea at all what the then-current binding for `even` is
> - it doesn't even look for "even" until the lambda is _executed_.
Just FYI, I still haven't managed to do it as 1-liner (well, one
statement). I expected the following would work, but it doesn't :-)
iseven = lambda n: (
lambda n=n, \
even = (lambda n: n == 0 or odd(n-1)), \
odd = (lambda n: False if n == 0 else even(n-1)):
even(n))()
Ugly and obscure, but why not? In the inner lambda, `n`, `even`, and
`odd` are all defined in its namespace, so why does it fail anyway?
>>> iseven(6)
Traceback (most recent call last):
...
iseven(6)
...
even(n))()
...
even = (lambda n: n == 0 or odd(n-1)), \
NameError: name 'odd' is not defined
Because while Python indeed doesn't capture the current binding for
`odd` when the `even` lambda is compiled, it _does_ recognize that the
name `odd` is not local to the lambda at compile-time, so generates a
LOAD_GLOBAL opcode to retrieve `odd`'s binding at runtime. But there
is no global `odd` (well, unless there is - and then there's no
guessing what the code would do).
For `even` to know at compile-time that `odd` will show up later in
its enclosing lambda's arglist requires that Python do `letrec`-style
binding instead. For a start ;-)
More information about the Python-ideas
mailing list