list of polynomial functions

Marc 'BlackJack' Rintsch bj_666 at gmx.net
Fri Jun 16 04:15:21 EDT 2006


In <mailman.7114.1150412705.27775.python-list at python.org>, Tim Chase
wrote:

> My understanding is that the lambda-defined functions are not 
> called until the actual application thereof, with the
> 
> 	mypolys = make_polys(8)
> 	mypolys[5](2) #the lambda call happens here, no?

Yes, that's right.

> </F>'s original statement read like a koan...there was more in it 
> than I was getting out of it.  There seem to be several concepts 
> I've not yet wrapped my head around.  My understanding (likely 
> wrong) was that "lambda" was sort of like defining a function 
> inline, along the lines of
> 
> 	def f(x):
> 		return x+5
> 
> being somewhat equiv to
> 
> 	k = lambda x: x+5
> 
> you could then do
> 
> 	>>> f(20)
> 	25
> 	>>> j = f
> 	>>> j(20)
> 	25
> 	>>> k(20)
> 	25
> 	>>> j = k
> 	>>> j(20)
> 	25
> 
> There does seem to be some subtle difference, as
> 
> 	>>> f
> 	<function f at 0xb7d87e9c>
> 	>>> k
> 	<function <lambda> at 0xb7d8c0d4>
> 
> "k" clearly knows it's a <lambda> just as "f" knows its an "f" 
> (whether asked for by the aliased name or not).

That understanding is mostly correct.  Just that there's no subtile
difference.  `k` doesn't know it's a lambda function, it's just an
ordinary function at this point which happens to have the name '<lambda>'.
That's somewhat unusual but it behaves like any ``def``-ed function.

> [lightbulb begins to go on...sorta]
> 
> However, in the OP's example, slightly modified, it seems that 
> polys, even when it doesn't exist in the calling scope, it 
> doesn't matter.
> 
>  >>> def mp(n):
> ...     p = lambda x: 1
> ...     polys = [p]
> ...     for i in range(n):
> ...             polys.append(lambda x: polys[i](x)*x)
> ...     return polys
> ...
>  >>> f = mp(5)
>  >>> polys
> Traceback (most recent call last):
>    File "<stdin>", line 1, in ?
> NameError: name 'polys' is not defined
>  >>> for p in f: print p(3)
> ...
> 1
> Traceback (most recent call last):
>    File "<stdin>", line 1, in ?
>    File "<stdin>", line 5, in <lambda>
> :
> :
> :
> 
> I'm curious why the very first attempt to call p(3) doesn't bomb 
> out with the NameError that "polys" wasn't defined before it even 
> got to the point of attempting to call it.

Well, because `polys` does not exist in the module scope.  But it exists
in the local scope of the functions in `f`.

An example:

 In [2]:def outer(a):
    .2.:    b = 42
    .2.:    def inner(c):
    .2.:        print a, b, c
    .2.:        print locals()
    .2.:
    .2.:    return inner
    .2.:

 In [3]:f = outer(1)

 In [4]:f(2)
 1 42 2
 {'a': 1, 'c': 2, 'b': 42}

If `outer` returns `inner` the inner function still has a reference to the
locals of the enclosing function.  So they won't go away if the outer
function returns.  `a` and `b` are looked up when `f` is called.  That's a
problem if you create more than one function in `outer` and use a name
from outer's locals that changes:

 In [7]:def pitfall():
    .7.:    functions = list()
    .7.:    for i in range(3):
    .7.:        functions.append(lambda: i)
    .7.:    print 'pitfall: i=%d' % i
    .7.:    return functions
    .7.:

 In [8]:for function in pitfall():
    .8.:    print function()
    .8.:
 pitfall: i=2
 2
 2
 2

At the time the list with the functions is returned `i` is 2.  So if you
call any of the functions it looks up this `i`.

Ciao,
	Marc 'BlackJack' Rintsch



More information about the Python-list mailing list