lambda

R

rubbishemail

Hello,

I need your help understanding lambda (and doing it a better way
without).

f = lambda x : x*x

# this is a list of functions
[f for y in range(1,5)]

[f for y in range(1,5)][0](2)
# returns 4, as expected


# ok now I want a list like
# [x^2, 2*x^2, 3*x^2,...]

[f*y for y in range(5)]
# this causes an unsupported operand type because it cannot multiply a
function and int

# the idea is now to give the definition of the multiplication of
functions and integers
# (f * c)(xx) := f(x)*c
[lambda xx: f(xx)*y for y in range(1,5)][0](1)
# returns 4
# I would expect 1*x*x = 1

# Where is my mistake and what would be the correct way to do this
without lambdas?

If you are interested in the reason for the code:

approxFunction gets a function and a list of x-values.
It computes func on these points and returns an interpolating
polynomial.
(this form of interpolation is often not stable, the code demonstrates
this)

def lagrangeBase(i, points):
"""returns the i-th lagrange polynomial on the nodes points (list
of xj)
In Symbolic notation the result should be
lagrangeBase(x)=\Pi_{j=0, j\ne i} (x-xj)/(xi-xj)
"""
xi = points
# all points without xi
nums = [points[x] for x in range(len(points)) if x!=i ]


# unsupported operand type * for functions, therefore the lambda xx
# what is the proper way to do this ?
return reduce(lambda a,b: lambda xx: a(xx)*b(xx) , map(lambda xj:
lambda x: (x-xj)/(xi-xj), nums))


def approxFunction(func, points):
"""this returns an approximation polynomial for func on the nodes
points
\Sum lagrangeBase(x_i) func(x_i)
"""
funcValues = [func(x) for x in points]



# this is the problem mentioned above
# sumTerms = [lambda xx: lagrangeBase(i, points)(xx)*funcValues
for i in range(len(points))]

# this works
sumTerms = map(lambda i: lambda xx : lagrangeBase(i, points)(xx) *
funcValues, range(len(points)))
return reduce(lambda a,b: lambda xx: a(xx)+b(xx), sumTerms)



I am using
Python 2.4.1 (#65, Mar 30 2005, 09:13:57) [MSC v.1310 32 bit (Intel)]
Type "copyright", "credits" or "license" for more information.

IPython 0.6.13 -- An enhanced Interactive Python.



Many thanks


Daniel
 
B

Ben C

Hello,

I need your help understanding lambda (and doing it a better way
without).

f = lambda x : x*x
[...]
# the idea is now to give the definition of the multiplication of
functions and integers
# (f * c)(xx) := f(x)*c
[lambda xx: f(xx)*y for y in range(1,5)][0](1)
# returns 4
# I would expect 1*x*x = 1

If you change the 5 in range(1,5) to a 10, this returns 9.

So it looks like each of the lambda xx : f(xx) * y is getting the last
value of y.

I can do this for example:

f = lambda x : x * x
fns = [lambda xx: f(xx)*y for y in range(1,10)]
for fn in fns:
print fn(1)

And I get 9 printed out 9 times.

It does seem a bit surprising, but I suppose if you think about it
there's only one "y"-- the one in the outer scope. This one variable is
bound 9 times, to a new value each time.

What one would need for it to work would be for each of the functions to
have a variable in its own scope. But you can't, as far as I know,
create local variables in functions defined with lambda.
 
M

Mel Wilson

Hello,

I need your help understanding lambda (and doing it a better way
without).

f = lambda x : x*x [ ... ]
# the idea is now to give the definition of the multiplication of
functions and integers
# (f * c)(xx) := f(x)*c
[lambda xx: f(xx)*y for y in range(1,5)][0](1)
# returns 4
# I would expect 1*x*x = 1

I think you have to get the value of y at definition time,
not at call time:
>>> z=[lambda xx, yy=y: (f(xx)*yy) for y in xrange(1,5)]
>>> z[0](1)
1

Mel.
 
A

Alexis Roda

(e-mail address removed) escribió:
Hello,

# the idea is now to give the definition of the multiplication of
functions and integers
# (f * c)(xx) := f(x)*c
[lambda xx: f(xx)*y for y in range(1,5)][0](1)
# returns 4

here lambda uses a variable defined outside of the lambda (y). Any
change made to y will be visible within the lambda. In your example the
last value for y is 4, so:

[...][0](1) = f(1) * 4 = 4
# I would expect 1*x*x = 1

you should use a local variable to "protect" y:

[ lambda xx, y=y : f(xx) * y for y in range(1, 5) ]
# Where is my mistake and what would be the correct way to do this
without lambdas?

You can emulate callables http://docs.python.org/ref/callable-types.html

class Callable:
def __init__(self, f, y) :
self.y = y
self.f = f
def __call__(self, x) :
return self.f(x) * self.y

f = lambda x : x * x

[ Callable(f, y) for y in range(1, 5) ]

if you *absolutely* don't want lambdas you can hard code the x*x in
__call__ and get rid of self._f, or you can define:

class Monomial:
def __init__(self, exp, coef) :
self.exp = exp
self.coef = coef
def __call__(self, x) :
return x ** self.exp * self.coef

[ Monomial(2, y) for y in range(1, 5) ]

Another way, somewhat convoluted, using closures:

def make_list() :
def make_function(y) :
def function(x) :
return x * x * y
return function
return [ make_function(y) for i in range(1, 5) ]

is essentially the same as lambda. Mostly didactic.



HTH
 
B

Ben C

Hello,

I need your help understanding lambda (and doing it a better way
without).

f = lambda x : x*x
[...]
# the idea is now to give the definition of the multiplication of
functions and integers
# (f * c)(xx) := f(x)*c
[lambda xx: f(xx)*y for y in range(1,5)][0](1)
# returns 4
# I would expect 1*x*x = 1

If you change the 5 in range(1,5) to a 10, this returns 9.

So it looks like each of the lambda xx : f(xx) * y is getting the last
value of y.

I can do this for example:

f = lambda x : x * x
fns = [lambda xx: f(xx)*y for y in range(1,10)]
for fn in fns:
print fn(1)

And I get 9 printed out 9 times.

It does seem a bit surprising, but I suppose if you think about it
there's only one "y"-- the one in the outer scope. This one variable is
bound 9 times, to a new value each time.

What one would need for it to work would be for each of the functions to
have a variable in its own scope. But you can't, as far as I know,
create local variables in functions defined with lambda.

Having said that, I attempted to confirm this using def rather than
lambda, and encountered something I cannot explain at all-- it appears
that the functions are getting redefined whenever they are called, to
effect a kind of "dynamic scoping" behaviour. I would appreciate any
explanation anyone can give of this:

fns = []
for y in range(2):
def fn():
yy = y # exactly the same with yy = int(y)
print "defining fn that returns", yy
return yy
print "Appending at", y
print fn, fn()
fns.append(fn)

print "OK"

for fn in fns:
print "Calling", fn
print fn, fn()

y = 10

for fn in fns:
print "Calling", fn
print fn, fn()

The output:

Appending at 0
<function fn at 0x402e317c> defining fn that returns 0
0
Appending at 1
<function fn at 0x402e31b4> defining fn that returns 1
1
OK
Calling <function fn at 0x402e317c>
<function fn at 0x402e317c> defining fn that returns 1
1
Calling <function fn at 0x402e31b4>
<function fn at 0x402e31b4> defining fn that returns 1
1
Calling <function fn at 0x402e317c>
<function fn at 0x402e317c> defining fn that returns 10
10
Calling <function fn at 0x402e31b4>
<function fn at 0x402e31b4> defining fn that returns 10
10
 
R

rubbishemail

Hello Alexis,

thank you for the fast help!
I am not against lambdas, but, sometimes they are a bit confusing to
me, especially as you don't see many examples used.


Daniel
 
A

Alexis Roda

Ben C escribió:
Having said that, I attempted to confirm this using def rather than
lambda, and encountered something I cannot explain at all-- it appears
that the functions are getting redefined whenever they are called, to
effect a kind of "dynamic scoping" behaviour. I would appreciate any
explanation anyone can give of this:

fns = []
for y in range(2):
def fn():
yy = y # exactly the same with yy = int(y)
print "defining fn that returns", yy
return yy
print "Appending at", y
print fn, fn()
fns.append(fn)


yy = y does assign y's current value (current == fn call time, not fn
definition time). To return 0 and 1 as expected you should create a
"different/private" y for every fn's definition.

----------------------------------------

fns = []
for y in range(2):
def fn(y=y):
yy = y
print "defining fn that returns", yy
return yy
print "Appending at", y
print fn, fn()
fns.append(fn)


----------------------------------------

fns = []
def factory(y) :
def fn() :
yy = y
print "defining fn that returns", yy
return yy
return fn

for y in range(2) :
fn = factory(y)
print "Appending at", y
print fn, fn()
fns.append(fn)
 
B

Ben C

Ben C escribió:
Having said that, I attempted to confirm this using def rather than
lambda, and encountered something I cannot explain at all-- it appears
that the functions are getting redefined whenever they are called, to
effect a kind of "dynamic scoping" behaviour. I would appreciate any
explanation anyone can give of this:

fns = []
for y in range(2):
def fn():
yy = y # exactly the same with yy = int(y)
print "defining fn that returns", yy
return yy
print "Appending at", y
print fn, fn()
fns.append(fn)


yy = y does assign y's current value (current == fn call time, not fn
definition time). To return 0 and 1 as expected you should create a
"different/private" y for every fn's definition.

----------------------------------------

fns = []
for y in range(2):
def fn(y=y):
yy = y
print "defining fn that returns", yy
return yy
print "Appending at", y
print fn, fn()
fns.append(fn)


----------------------------------------

Yes; the difficulty is that the body of the function is executed
(obviously) every time you call it. The body of the function reads y
which is a global variable and has whatever value it has at the time.

The parameters are the only part of a function definition where you get
to write some code that initializes things in the function's "frame"
when the function is defined rather than when it's called.

I got confused because I was thinking of yy = y in the body of fn's
definition as an initialization, not as an assignment. In other
languages it's possible to distinguish, but not in Python.

Really this is what classes are for in Python:

def f(x):
return x * x

class fn(object):
def __init__(self, y):
# "define-time" things are here
self.y = y

def __call__(self, x):
# "call-time" things are here
return f(x) * self.y

fns = [fn(i) for i in range(1, 10)]
for f in fns:
print f(1)

is I think quite a good way to do this.
 
T

Terry Reedy

Hello,

I need your help understanding lambda (and doing it a better way
without).

f = lambda x : x*x

There is no reason to ever write name=lambda...

def f(x): return x*x

is better because it attaches the name to the function for tracebacks.
# this is a list of functions
[f for y in range(1,5)]

[f for y in range(1,5)][0](2)
# returns 4, as expected


# ok now I want a list like
# [x^2, 2*x^2, 3*x^2,...]

Given:

def makef(multiplier):
def f(x): return multiplier*x*x
return f
[f*y for y in range(5)]

I believe

[makef(y) for y in range(5)]

will do what you want.

The slightly abbreviated lambda form is never necessary, that I know of,
and notoriously confusing when used in list comprehensions. So I advise
don't.

Terry Jan Reedy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top