2

I'd like to assign a variable to the scope of a lambda that is called several times. Each time with a new instance of the variable. How do I do that?

f = lambda x: x + var.x - var.y

# Code needed here to prepare f with a new var

result = f(10)

In this case it's var I'd like to replace for each invocation without making it a second argument.

Jonas K
  • 4,215
  • 2
  • 24
  • 25
  • 2
    don't use a `lambda`, use a regular function, you shouldn't feel the need to use `lambda`s whenever possible – jamylak May 15 '13 at 08:05
  • 2
    In general, if a lambda is complex enough that you have to ask how to contort it to accomplish a task, just use a regular 'def' function. It will result it more readable, maintainable code. – Colin Valliant May 15 '13 at 08:07
  • @jamylak I agree. But lambda or regular function, I'm not sure how the OP wants to accomplish what he's asking. How do you change something in the scope of a function, without using an argument? – Jonathon Reinhart May 15 '13 at 08:09
  • You can replace the lambda with a regular function if that helps. I just need to somehow manipulate the functions local variables/closure. – Jonas K May 15 '13 at 08:11
  • 1
    possible duplicate of [How to modify the local namespace in python](http://stackoverflow.com/questions/1142068/how-to-modify-the-local-namespace-in-python) or [How to dynamically modify a function's local namespace?](http://stackoverflow.com/questions/10488296/how-to-dynamically-modify-a-functions-local-namespace) @JonathonReinhart there are a few ways but no clean ones as seen in those links – jamylak May 15 '13 at 08:14
  • @jamylak That's referring to *namespace*. Does that really apply to function-scoped variables? – Jonathon Reinhart May 15 '13 at 08:24
  • @JonathonReinhart yes, also OP specified that he can't add another argument to the `lambda` definition so there is no other way – jamylak May 15 '13 at 08:26
  • @jamylak Right. The whole thing is starting to seem absurd :-P – Jonathon Reinhart May 15 '13 at 08:30
  • The lambda is defined externally and out of my control, but I want to provide a scope for the lambda creators. Does that make it make more sense? – Jonas K May 15 '13 at 08:36

4 Answers4

9

Variables undefined in the scope of a lambda are resolved from the calling scope at the point where it's called.

A slightly simpler example...

>>> y = 1
>>> f = lambda x: x + y
>>> f(1)
2
>>> y = 2
>>> f(1)
3

...so you just need to set var in the calling scope before calling your lambda, although this is more commonly used in cases where y is 'constant'.

A disassembly of that function reveals...

>>> import dis
>>> dis.dis(f)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_GLOBAL              0 (y)
              6 BINARY_ADD
              7 RETURN_VALUE

If you want to bind y to an object at the point of defining the lambda (i.e. creating a closure), it's common to see this idiom...

>>> y = 1
>>> f = lambda x, y=y: x + y
>>> f(1)
2
>>> y = 2
>>> f(1)
2

...whereby changes to y after defining the lambda have no effect.

A disassembly of that function reveals...

>>> import dis
>>> dis.dis(f)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 BINARY_ADD
              7 RETURN_VALUE
Aya
  • 39,884
  • 6
  • 55
  • 55
  • While this is nifty, and what the OP was asking for, I feel sorry for the poor shmuck that has to maintain this. "Where the hell is `y` coming from in this lambda?!" It may be obvious in this example, but not in a larger project. Remember the python idiom "explicit over implicit"... I don' think this is explicit. – Jonathon Reinhart May 22 '13 at 06:42
  • 1
    @JonathonReinhart I agree. I mainly posted this because the other answers implied that it wasn't possible, so I just wanted to demonstrate that it was *possible*. Whether or not it's a *good idea* is subjective. There's probably a better solution for what the OP wants to achieve, but the original question doesn't really contain enough info to make that determination. – Aya May 22 '13 at 11:27
1

f = functools.partial(lambda var, x: x + var.x - var.y, var) will give you a function (f) of one parameter (x) with var fixed at the value it was at the point of definition.

0

You cannot use the assignment statement in lambda expression, so you'll have to use a regular named function:

def f(x):
    global var
    var = x

Note the use of the "global" keyword. Without it, Python will assume you want to create a new "var" variable in the local scope of the function.

adolfopa
  • 82
  • 5
-1

Make it another parameter:

f = lambda x,var: x + var.x - var.y
result = f(10, var)

Lambda or regular function, the only way you can change a variable in the scope of a function is via an argument.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • Thanks, that was my first thought, but I want to avoid a second argument. – Jonas K May 15 '13 at 08:04
  • 1
    Well then how else can you do it? How do you possibly control what `var` is for each invocation of `f`? – Jonathon Reinhart May 15 '13 at 08:05
  • In that case yes, re-define the lambda every place you want to use it. Seems silly and convoluted. (aka difficult to understand, maintain, etc.) – Jonathon Reinhart May 15 '13 at 08:10
  • Why *avoid a second argument*? If you want two pieces of data, why obscure that? – Gareth Latty May 15 '13 at 08:13
  • Yes, that would not be an acceptable solution, maybe this is impossible. – Jonas K May 15 '13 at 08:13
  • The reason to avoid two arguments is that the second would seldom be used but some cases needs it and I want to keep the lambda as trivial as possible. – Jonas K May 15 '13 at 08:19
  • 1
    Okay, but when it's not used, what is `var` then? This becomes so complicated. Perhaps you need to provide more information/code to help us understand what *exactly* you're trying to do. I would consider deleting this entire question and starting over. – Jonathon Reinhart May 15 '13 at 08:22