Question about lambda and variable bindings

castironpi at gmail.com castironpi at gmail.com
Sat Mar 1 22:22:03 EST 2008


On Mar 1, 8:50 pm, Michael Torrie <torr... at gmail.com> wrote:
> 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:
>
> >>> dis.dis(funcs[0])
>
>   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 )



More information about the Python-list mailing list