473,386 Members | 1,766 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,386 software developers and data experts.

Functional programming gotcha


Hi all,

I find this strange:
flist = []
for i in range(3): .... f = lambda x: x+i
.... flist.append(f)
.... [f(1) for f in flist] [3, 3, 3]
What I expect is:
[f(1) for f in flist] [1,2,3]
Is this a bug in Python? It happens on my builds of
Python 2.3 and 2.2.3.

Replacing the lambda function by a named function, as in

flist = []
for i in range(3):
def f(x):
return x + i
flist.append(f)

[f(1) for f in flist]

gives the same result.

I have a workaround (of sorts) adapted from the Python tutorial:
def make_incrementor(n): .... return lambda x: x + n
.... flist = [make_incrementor(i) for i in range(3)]

[f(1) for f in flist] [1, 2, 3]


but I'd prefer the flexibility of the first approach. Any ideas?

Any explanations for why Python does this? Any justifications for why
Python _should_ do this? Who believes this is a bug?

Kind regards,
Ed Schofield

Jul 18 '05 #1
6 1609
Ed Schofield wrote:
Hi all,

I find this strange:

flist = []
for i in range(3):
... f = lambda x: x+i
... flist.append(f)
...
[f(1) for f in flist]
[3, 3, 3]
What I expect is:

[f(1) for f in flist]
[1,2,3]
Is this a bug in Python? It happens on my builds of
Python 2.3 and 2.2.3.
I guess the nested scopes changes in Python 2.1/2.2 (see
http://www.python.org/peps/pep-0227.html) apply to functions but not
loops. You can use the same workaround that people used to use because
of the lack of nested scopes:

f = lambda x, i = i: x + i

That way, the second, optional parameter has a default value which is
evaluated at the time the lambda is created.

Replacing the lambda function by a named function, as in

flist = []
for i in range(3):
def f(x):
return x + i
flist.append(f)

[f(1) for f in flist]

gives the same result.

I have a workaround (of sorts) adapted from the Python tutorial:

def make_incrementor(n):
... return lambda x: x + n
...
flist = [make_incrementor(i) for i in range(3)]

[f(1) for f in flist]


[1, 2, 3]
but I'd prefer the flexibility of the first approach. Any ideas?

Any explanations for why Python does this? Any justifications for why
Python _should_ do this? Who believes this is a bug?

Kind regards,
Ed Schofield


Jul 18 '05 #2
In article <Pi*************************************@tethys.ft w.at>, Ed
Schofield <sc*******@ftw.at> writes

Hi all,

I find this strange:
flist = []
for i in range(3):... f = lambda x: x+i
try using f = lambda x,i=i: x+i ie bind at the definition point
... flist.append(f)
... [f(1) for f in flist][3, 3, 3]
What I expect is:
[f(1) for f in flist][1,2,3]
Is this a bug in Python? It happens on my builds of
Python 2.3 and 2.2.3.

Replacing the lambda function by a named function, as in

flist = []
for i in range(3):
def f(x):
return x + i
flist.append(f)

[f(1) for f in flist]

gives the same result.

I have a workaround (of sorts) adapted from the Python tutorial:
def make_incrementor(n):... return lambda x: x + n
... flist = [make_incrementor(i) for i in range(3)]

[f(1) for f in flist][1, 2, 3]


but I'd prefer the flexibility of the first approach. Any ideas?

Any explanations for why Python does this? Any justifications for why
Python _should_ do this? Who believes this is a bug?

Kind regards,
Ed Schofield


--
Robin Becker
Jul 18 '05 #3
David C. Fox wrote:
Ed Schofield wrote:
Hi all,

I find this strange:

> flist = []
> for i in range(3):

... f = lambda x: x+i
... flist.append(f)
...
> [f(1) for f in flist]

[3, 3, 3]
What I expect is:

> [f(1) for f in flist]

[1,2,3]
Is this a bug in Python? It happens on my builds of
Python 2.3 and 2.2.3.

I guess the nested scopes changes in Python 2.1/2.2 (see
http://www.python.org/peps/pep-0227.html) apply to functions but not
loops.


I take back that explanation. The problem is that the i in the lambda
*does* refer to the local variable i, whose value changes as you go
through the loop, not to a new variable whose value is equal to the
value of i at the time when the lambda was created.

The workaround is still the same:
loops. You can use the same workaround that people used to use because
of the lack of nested scopes:

f = lambda x, i = i: x + i

That way, the second, optional parameter has a default value which is
evaluated at the time the lambda is created.


David

Jul 18 '05 #4


David C. Fox schrieb:
.....

I guess the nested scopes changes in Python 2.1/2.2 (see
http://www.python.org/peps/pep-0227.html) apply to functions but not
loops. You can use the same workaround that people used to use because
of the lack of nested scopes:

f = lambda x, i = i: x + i

That way, the second, optional parameter has a default value which is
evaluated at the time the lambda is created.


Isn't this the intended behaviour of nested scopes (regardless
of loops or not)?
def fun(): i = 1
def f():
print i
f()
i+=1
f()

fun() 1
2


Gregor

Jul 18 '05 #5

"Ed Schofield" <sc*******@ftw.at> wrote in message
news:Pi*************************************@tethy s.ftw.at...

Hi all,

I find this strange:
flist = []
for i in range(3): ... f = lambda x: x+i
... flist.append(f)
... [f(1) for f in flist] [3, 3, 3]
What I expect is:
[f(1) for f in flist]

[1,2,3]


Others have given the solution, but let's think about the why of it.
If a function in a dyanamic language (one that allows runtime
construction of functions) has a free variable (one not set within the
function), the question arises "When do we get (capture) the value of
the variable? At definition/construction time or at call/execution
time? Or, to put it another way, what do we capture? The (current)
value of the variable or its name (for later evaluation). Either
could be what we want.

Python lets you choose which capture method (evaluation time) you
want. Do nothing to get the name captured for later evaluation. Or
put v=v in the arglist to capture the current value and give it the
same name (w=v, to use a new name, is legal too, of course).

Terry J. Reedy
Jul 18 '05 #6

"Terry Reedy" <tj*****@udel.edu> wrote in message news:WY********************@comcast.com...

<...>

Others have given the solution, but let's think about the why of it.
If a function in a dyanamic language (one that allows runtime
construction of functions) has a free variable (one not set within the
function), the question arises "When do we get (capture) the value of
the variable? At definition/construction time or at call/execution
time? Or, to put it another way, what do we capture? The (current)
value of the variable or its name (for later evaluation). Either
could be what we want.

Python lets you choose which capture method (evaluation time) you
want. Do nothing to get the name captured for later evaluation. Or
put v=v in the arglist to capture the current value and give it the
same name (w=v, to use a new name, is legal too, of course).

Terry J. Reedy


Very good and simple explanation! Thank you.

Georgy

Jul 18 '05 #7

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

Similar topics

8
by: beza1e1 | last post by:
I see myself shifting more and more over to the functional kind of coding. Could be related to the Haskell, we had to learn in CS. Now i was wondering, how other people use Python? With...
177
by: C# Learner | last post by:
Why is C syntax so uneasy on the eye? In its day, was it _really_ designed by snobby programmers to scare away potential "n00bs"? If so, and after 50+ years of programming research, why are...
60
by: Shawnk | last post by:
Some Sr. colleges and I have had an on going discussion relative to when and if C# will ever support 'true' multiple inheritance. Relevant to this, I wanted to query the C# community (the...
5
by: shumaker | last post by:
I just read an overview of C# 3.0, and it occured to me that some of these features could make it much easier to write programs that automatically make use of multi core processors. After reading...
4
by: Casey Hawthorne | last post by:
Can Your Programming Language Do This? Joel on functional programming and briefly on anonymous functions! http://www.joelonsoftware.com/items/2006/08/01.html -- Regards, Casey
15
by: Lorenzo Stella | last post by:
Hi all, I haven't experienced functional programming very much, but now I'm trying to learn Haskell and I've learned that: 1) in functional programming LISTS are fundmental; 2) any "cycle" in FP...
139
by: Joe Mayo | last post by:
I think I become more and more alone... Everybody tells me that C++ is better, because once a project becomes very large, I should be happy that it has been written in C++ and not C. I'm the only...
0
by: happycow2 | last post by:
Hi, I first want to start off by saying that I’m not a programmer but rather a 3-D animation/ special effects student, however there are allot of concepts that i come across that are some what...
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...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
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
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,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

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.