473,387 Members | 1,575 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

lambda trouble

Hi!

I was doing something like this:
def p( x ): .... print x
.... l = []
for i in range( 5 ): .... l.append( lambda: p( i ) )
.... for k in l: .... k()
....
4
4
4
4
4

And it surprised me a little. I was expecting to see 0, 1, 2, 3, 4.
After some brainwork I now kind of understand what happens and I even
found a solution like this:
def mylambda( fn, *args ): .... return lambda: apply( fn, args )
.... l = []
for i in range( 5 ): .... l.append( mylambda( p, i ) )
.... for k in l:

.... k()
....
0
1
2
3
4

But I still feel a bit unsatisfied. Do you have some advice for me?

Cheers,

Daniel
Jul 18 '05 #1
9 1623

Darabos Daniel wrote:
And it surprised me a little. I was expecting to see 0, 1, 2, 3, 4.
After some brainwork I now kind of understand what happens and I even
found a solution like this:

Well, it is not suprising. In a lambda expression, everything after the
: is symbolic. It is compiled,
not evaluated. You can use a named function instead of an unnamed one:

[GCC 3.3.3 [FreeBSD] 20031106] on freebsd5
Type "help", "copyright", "credits" or "license" for more information.
def p(x): .... print x
.... l = []
for i in range( 5 ): .... def func():
.... p(i)
.... l.append( func )
.... for k in l: .... k()
.... l [<function func at 0x81a4f0c>, <function func at 0x81a4f44>, <function
func at 0x81a4f7c>, <function func at 0x81a4fb4>, <function func at
0x81ae02c>]


You have different functions. However, in every function, the name 'i'
is not a local name. (Python has only two levels: local and global.)
Here is another solution. However, it uses eval. Probably, it is not the
fastest one.

def p(x):
print x

l = []
for i in range( 5 ):
l.append(eval("lambda: p( %s )"%i))

for k in l:
k()
Udv,

Laci
Jul 18 '05 #2
Gandalf wrote:

Darabos Daniel wrote:
And it surprised me a little. I was expecting to see 0, 1, 2, 3, 4.
After some brainwork I now kind of understand what happens and I even
found a solution like this:

Well, it is not suprising. In a lambda expression, everything after the
: is symbolic. It is compiled,
not evaluated. You can use a named function instead of an unnamed one:

[GCC 3.3.3 [FreeBSD] 20031106] on freebsd5
Type "help", "copyright", "credits" or "license" for more information.
>>> def p(x): ... print x
... >>> l = []
>>> for i in range( 5 ): ... def func():
... p(i)
... l.append( func )
... >>> for k in l: ... k()
... >>> l [<function func at 0x81a4f0c>, <function func at 0x81a4f44>, <function
func at 0x81a4f7c>, <function func at 0x81a4fb4>, <function func at
0x81ae02c>] >>>
You have different functions. However, in every function, the name 'i'
is not a local name. (Python has only two levels: local and global.)
Here is another solution. However, it uses eval. Probably, it is not the
fastest one.

def p(x):
print x

l = []
for i in range( 5 ):
l.append(eval("lambda: p( %s )"%i))

for k in l:
k()
Udv,

Laci

It is really even simpler:
def p(x): print x
l=[lambda i=i: p(i) for i in range(5)]
for k in l: k()

0
1
2
3
4


Jul 18 '05 #3

"Darabos Daniel" <cy****@sch.bme.hu> wrote in message
news:Pine.GSO.4.58L0.0403191736410.14978@balu...
Hi!

I was doing something like this:
def p( x ): ... print x
... l = []
for i in range( 5 ): ... l.append( lambda: p( i ) )
... for k in l: ... k()
...
4
4
4
4
4

And it surprised me a little. I was expecting to see 0, 1, 2, 3, 4.
If you had written

for i in range(5):
def f(): return p(i)
l.append(f)

would you have still been surprised? Or given that f is constant, how
about the exactly equivalent

def f(): return p(i)
for i in range(5):
l.append(f)

or even the equivalent

def f(): return p(j)
for i in range(5):
l.append(f)
j=i
def p(z): print z
<etc>

After some brainwork I now kind of understand what happens and I even
found a solution like this:
def mylambda( fn, *args ): ... return lambda: apply( fn, args )
... l = []
for i in range( 5 ): ... l.append( mylambda( p, i ) )
... for k in l:

... k()
...
0
1
2
3
4

But I still feel a bit unsatisfied. Do you have some advice for me?


Remember that 1) 'lambda args: expr' basically abbreviates 'def f(args):
return expr'; and 2) function code bodies only execute when the function
is called, and in particular, do not dereference or access globals until
called. While a function is being constructed, it is irrelevant that a
global even exist, let along that it be in use as a loop var.

Terry J. Reedy


Jul 18 '05 #4
On 19 Mar 2004, Darabos Daniel <- cy****@sch.bme.hu wrote:
def p( x ): ... print x
... l = []
for i in range( 5 ): ... l.append( lambda: p( i ) )
... for k in l: ... k()
...
4
4
4
4
4 And it surprised me a little. I was expecting to see 0, 1, 2, 3, 4.
The `i' in your code is bound to the global value of `i' which is 4.
After some brainwork I now kind of understand what happens and I even
found a solution like this:
def mylambda( fn, *args ): ... return lambda: apply( fn, args )

[...]
But I still feel a bit unsatisfied. Do you have some advice for me?


You have to bind the value of `i' in the lambda form; you did that with
your function definition but it can be done a bit simpler:
funs = [lambda i=i: sys.stdout.write(str(i)+"\n") for i in range(4)]
for f in funs: .... f()
....
0
1
2
3


With the `i=i' the `i' in the lambda got bound.
KP

--
And has thou slain the Jabberwock?
Come to my arms, my beamish boy!
O frabjous day! Callooh! Callay!'
He chortled in his joy. "Lewis Carroll" "Jabberwocky"
Jul 18 '05 #5
Darabos Daniel <cy****@sch.bme.hu> wrote:

:>>> def p( x ):
: ... print x
: ...
:>>> l = []
:>>> for i in range( 5 ):
: ... l.append( lambda: p( i ) )
: ...
:>>> for k in l:
: ... k()
: ...
: 4
: 4
: 4
: 4
: 4

: And it surprised me a little. I was expecting to see 0, 1, 2, 3, 4.
Hi Darabos,
Someone should make a FAQ out of this. *grin*
This keeps popping up every so often on comp.lang.python. Here's a
link to one of the really heated threads about this:

http://groups.google.com/groups?hl=e...0119375&rnum=6
It sounds like you may have some experience with some kind of
functional language like Scheme. If so, then you probably understand
the distinction between DEFINE and SET! in Scheme.
The issue that you're running into is that Python uses a SET!-like
behavior when it reassigns the index variable of loops. To see this
more easily, let me translate your program into an equivalent Scheme
program:

;;;
guile> (define (p x) (display x) (newline))
guile> (define l '())
guile> (define i 0)
guile> (while (< i 5)
(begin
(set! l (cons (lambda () (p i)) l))
(set! i (+ i 1))))
guile> (for-each (lambda (x) (x)) l)
5
5
5
5
5
;;;

So here we can see the same problem popping up.

: found a solution like this:
:>>> def mylambda( fn, *args ):
: ... return lambda: apply( fn, args )
: ...
:>>> l = []
:>>> for i in range( 5 ):
: ... l.append( mylambda( p, i ) )
: ...
Yup, this works, because we take advantage of the name-binding
behavior of parameter passing. Another way of saying the same thing
is:

###
def make_p(x): .... def p():
.... print x
.... return p
.... l = []
for i in range(5): .... l.append(make_p(i))
.... for k in l:

.... k()
....
0
1
2
3
4
###
It's the issue of DEFINE vs. SET! --- the first assignment in Python
acts like DEFINE, and subsequence reassignments act like SET!. So
just one thing to be careful about with assignment.
I hope this helps!
Jul 18 '05 #6
Daniel Yoo <dy**@hkn.eecs.berkeley.edu> wrote in message news:<c3**********@agate.berkeley.edu>...

Someone should make a FAQ out of this. *grin*
Just to know, how does it work? If I write a FAQ entry, who is in
charge
of putting it in the official FAQ? (I don't have the time to write
down
this specific FAQ now, but I may be willing to write down a FAQ in the
future).
This keeps popping up every so often on comp.lang.python. Here's a
link to one of the really heated threads about this:

http://groups.google.com/groups?hl=e...0119375&rnum=6


Here is a non-trollish thread on the subject, which may also
be interesting if you know some Lisp/Scheme:

http://groups.google.it/groups?hl=it....lang.python.*

HTH,

Michele Simionato
Jul 18 '05 #7
The problem, they say, is that a variable in a FOR clause can't bind a variable
inside a lambda abstraction. Fortunately the lambda operator itself doesn't
share this limitation, so you can make the variable visible to the binder in the
FOR clause by binding with a lambda and then evaluating the resulting
abstraction at the variable in question, like so:
def p(x): print x
list=[]
for i in range(5): list.append((lambda j: lambda: p(j))(i))
x=map(lambda f: f(),list) 0
1
2
3
4

Or, more concisely,
def p(x): print x
list=[(lambda j: lambda: p(j))(i) for i in range(5)]
x=map(lambda f: f(),list)

0
1
2
3
4
Jul 18 '05 #8
"Elaine Jackson" <el***************@home.com> wrote in message news:<b397c.868228$X%5.57128@pd7tw2no>...
The problem, they say, is that a variable in a FOR clause can't bind a variable
inside a lambda abstraction.


I find this explanation confusing. It is just a matter of times:
the lambda uses the value of the bound name at *calling* time, not at
*definition* time:
i=1
f=lambda : i # definition time, i=1
i=2
f() # calling time, i has been rebound to 2 2
def p(x): print x
list=[(lambda j: lambda: p(j))(i) for i in range(5)]
x=map(lambda f: f(),list)


This works since the inner lambda uses the value of j at the calling time
of the outer lambda.

Just to clarifify the point for the OP, since I am sure you understand
the all story ;)
Michele Simionato
Jul 18 '05 #9
Darabos Daniel <cy****@sch.bme.hu> writes:
Do you have some advice for me?


I'll write the concise outline in words here. If you want a more
detailed explanation, then you could do worse than reading the thread
suggested by Michele. Therein he and I go into quite some
(excruciating and graphic :-) detail of what is going on.

The original problem is that there is a single binding of "i" which is
shared by all the lambdas you shove into "l". You want each lambda to
have its own, separate, binding of "i". To do this, you need to create
a new scope which binds "i" (originally, all the lambdas find "i" in
an outer scope). In Python, the only way to create a new nested scope
is with functions (which includes lambdas); any local variables in a
function are bound in a new inner scope. You sholuld create an i which
is local to your function (lambda), and bind it to the value you want.

For example:

lambda i=i: p(i)

Notes:

"i=i" means "i is a parameter (hence also a local variable) whose
default value is 'i at the time of function creation'" ...

.... therefore, the lambda now has its own "i", which is bound to the
value of the outer "i" at the time that the lambda form is being
evaluated.
Jul 18 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

8
by: Ian McMeans | last post by:
I was bitten by a bug today that depended on how lambda works. It took me quite a while to realize what was going on. First, I made multiple lambda functions inside a loop, each of which...
53
by: Oliver Fromme | last post by:
Hi, I'm trying to write a Python function that parses an expression and builds a function tree from it (recursively). During parsing, lambda functions for the the terms and sub-expressions...
26
by: Steven Bethard | last post by:
I thought it might be useful to put the recent lambda threads into perspective a bit. I was wondering what lambda gets used for in "real" code, so I grepped my Python Lib directory. Here are some...
4
by: markscottwright | last post by:
Just for the hell of it, I've been going through the old Scheme-based textbook "Structure and Interpretation of Computer Programs" and seeing what I can and can't do with python. I'm trying to...
181
by: Tom Anderson | last post by:
Comrades, During our current discussion of the fate of functional constructs in python, someone brought up Guido's bull on the matter: http://www.artima.com/weblogs/viewpost.jsp?thread=98196 ...
5
by: Max Rybinsky | last post by:
Hello! Please take a look at the example. >>> a = # Just a list of tuples >>> a Now i want to get a list of functions x*y/n, for each (x, y) in a:
267
by: Xah Lee | last post by:
Python, Lambda, and Guido van Rossum Xah Lee, 2006-05-05 In this post, i'd like to deconstruct one of Guido's recent blog about lambda in Python. In Guido's blog written in 2006-02-10 at...
5
by: Octal | last post by:
How does the lambda library actually works. How does it know how to evaluate _1, how does it recognize _1 as a placeholder, how does it then calculate _1+_2, or _1+2 etc. The source files seem a...
1
by: Tim H | last post by:
Compiling with g++ 4: This line: if_then_else_return(_1 == 0, 64, _1) When called with a bignum class as an argument yields: /usr/include/boost/lambda/if.hpp: In member function 'RET...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.