Theoretical question about Lambda

Alex Martelli aleax at aleax.it
Mon May 6 11:15:59 EDT 2002


Paul Foley wrote:
        ...
> OK; question: what's the difference, if any, between
> 
>      x = n
>      do_something
> 
> and
> 
>      def foo(x):
>         do_something
> 
>      foo(n)
> 
> as far as x is concerned?

Assuming these snippets are top-level code, "the difference as
far as x is concerned" is clearly that x is a global name in the
first snippet, and a local name of foo in the second snippet.


> Given that (lambda: x) /does/ close over x with nested scopes enabled,
> can you explain why
> 
>   fns = getfns(seq)
> 
> produces a list of functions that all return seq[-1]?  And why, as you

Because "lambda: x" is a callable that returns whatever object name x is 
bound to at the time it's called (rather than, at the time it's created).

It does not matter what name x was bound to, or even if it was indeed
bound at all, at creation time.  Only calling-time matters here.

What _scope_ matters for the binding of name x is determined by nested 
lexical scoping, but doesn't affect the rule.  And getfns last binds the 
relevant name x to seq[-1] before any of said functions are in fact called.

More generally, any form "lambda: <expression>" evaluates the <expression>
each time it's called.  It does not matter what value the expression had
(or even if it was evaluatable at all) at the time the lambda-form function 
was created; only calling time matters here.  The _scope_ in which the
expression is (at each call) evaluated IS determined at creation time,
however.

> point out,
> 
>   def getfns2(seq):
>      return [(lambda x=x: x) for x in seq]
> 
> produces functions that return all the elements of seq?
> [Assume you call them with no arguments!]

Because "lambda x=x: x" is a callable that (when called with no arguments)
returns whatever object name x was bound to at the time the callable was 
created (rather than, at the time it's called).  It does not matter what
name x is bound to, or even if it's indeed bound at all, at calling time.
Only creation time matters here.

More generally, any form "lambda x=<expression>: x" evaluates the 
<expression> only once, when the lambda-form is created.  It does not 
matter what value the expression has (or even if it is evaluatable at all) 
at the time the lambda-form function is called; only creation time matters 
here.  The _scope_ in which the expression is (at lambda's creation) 
evaluated IS also determined at creation time.


It makes no difference in all this that we're talking about a lambda-form
rather than a normal named function.  Exactly the same semantics apply
to named functions (it's just a bit easier to talk about them:-):

        def nolambda1(): return <expression>

evaluates the expression anew each time it's called (in the scope that
is determined when the def statement is executed).

        def nolambda2(x=<expression>): return x

evaluates the expression only once (once each time this def statement is 
executed, that is) and binds the resulting object as the default value for 
name x in the local scope of this new function object 'nolambda2'.  
Whenever nolambda2 is called without arguments, it returns that selfsame 
object that this def statement bound as the default value for name x in the 
local scope of this function nolambda2.


Alex




More information about the Python-list mailing list