Question about lambda and variable bindings

M

Michael Torrie

I need to use a lambda expression to bind some extra contextual data
(should be constant after it's computed) to a call to a function. I had
originally thought I could use something like this demo (but useless) code:

funcs=[]

def testfunc(a,b):
print "%d, %d" % (a,b)

for x in xrange(10):
funcs.append(lambda p: testfunc(x+2,p))


Now what I'd like is to call, for example, funcs[0](4) and it should
print out "2,4". In other words I'd like the value of x+2 be encoded
into the lambda somehow, for funcs[x]. However the disassembly shows
this, which is reasonable, but not what I need:
2 0 LOAD_GLOBAL 0 (testfunc)
3 LOAD_GLOBAL 1 (x)
6 LOAD_CONST 0 (2)
9 BINARY_ADD
10 LOAD_FAST 0 (p)
13 CALL_FUNCTION 2
16 RETURN_VALUE

The LOAD_GLOBAL 1 (x) line is definitely a problem. For one it refers
to a variable that won't be in scope, should this lambda be called from
some stack frame not descended from the one where I defined it.

So how can I create a lambda expression that calculates a constant based
on an expression, rather than referring to the object itself? Can it be
done?

Michael
 
C

castironpi

I need to use a lambda expression to bind some extra contextual data
(should be constant after it's computed) to a call to a function.  I had
originally thought I could use something like this demo (but useless) code:

funcs=[]

def testfunc(a,b):
    print "%d, %d" % (a,b)

for x in xrange(10):
    funcs.append(lambda p: testfunc(x+2,p))

Now what I'd like is to call, for example, funcs[0](4) and it should
print out "2,4".  In other words I'd like the value of x+2 be encoded
into the lambda somehow, for funcs[x].  However the disassembly shows
this, which is reasonable, but not what I need:

  2           0 LOAD_GLOBAL              0 (testfunc)
              3 LOAD_GLOBAL              1 (x)
              6 LOAD_CONST               0 (2)
              9 BINARY_ADD
             10 LOAD_FAST                0 (p)
             13 CALL_FUNCTION            2
             16 RETURN_VALUE

The LOAD_GLOBAL 1 (x) line is definitely a problem.  For one it refers
to a variable that won't be in scope, should this lambda be called from
some stack frame not descended from the one where I defined it.

So how can I create a lambda expression that calculates a constant based
on an expression, rather than referring to the object itself?  Can it be
done?

Michael

I hate that. Especially since ints are immutable.
from functools import partial
funcs= [ partial( print, x ) for x in range( 10 ) ]
for func in funcs:
... func()
...
0
1
2
3
4
5
6
7
8
9
takes advantage of 2.5+ functools.partial and 3.0 print. You can use
sys.stdout instead of print in the example in 2.5, but without
partial, you're at:

class Val:
def __init__( self, val ):
self.val= val
def __call__( self ):
self.val+= 10

val= Val( 20 )
val()

. There's also a CellMaker implementation somewhere on Py-Ideas, but
it was outlawed in 18 provinces, and it just evaluates and compiles a
string anyway.

for x in xrange(10):
fun= exec( 'lambda p: testfunc(%i+2,p)'% x )
funcs.append( fun )
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top