简体   繁体   中英

Can you assign variables in a lambda?

I was using a lambda statement to perform math, and happened to repeatedly use one certain value. Therefore I was wondering if it was possible to assign and use a variable within a lambda statement.

I have tried things like:

a = lambda n:(b=3+2*n) #[my math here]

However this just raises errors, and I was wondering if there was a way to do this.

Nope, you can't. Only expressions allowed in lambda :

 lambda_expr ::= "lambda" [parameter_list]: expression lambda_expr_nocond ::= "lambda" [parameter_list]: expression_nocond

You could, however, define a second lambda inside the lambda and immediately call it with the parameter you want. (Whether that's really better might be another question.)

>>> a = lambda n: ((3+2*n), n*(3+2*n))  # for reference, with repetition
>>> a(42)
(87, 3654)
>>> a2 = lambda n: (lambda b: (b, n*b))(3+2*n)  # lambda inside lambda
>>> a2(42)
(87, 3654)
>>> a3 = lambda n: (lambda b=3+2*n: (b, n*b))()  # using default parameter
>>> a3(42)
(87, 3654)

Of course, both the outer and the inner lambda can have more than one parameter, ie you can define multiple "variables" at once. The benefit of this approach over, eg, defining a second lambda outside of the first is, that you can still also use the original parameters (not possible if you invoked a with b pre-calculated) and you have to do the calculation for b only once (other than repeatedly invoking a function for the calculation of b within a ).


Also, inspired by the top answer to the linked question , you could also define one or more variables as part of a list comprehension or generator within the lambda, and then get the next (first and only) result from that generator or list:

>>> a4 = lambda n: next((b, n*b) for b in [3+2*n])
>>> a4(42)
(87, 3654)

However, I think the intent behind the lambda-in-a-lambda is a bit clearer. Finally, keep in mind that instead of a one-line lambda , you could also just use a much clearer three-line def statement...


Also, starting with Python 3.8, there will be assignment expressions , which should make it possible to write something like this. (Tested with Python 3.8.10.)

>>> a5 = lambda n: ((b := 3+2*n), n*b)

You can assign variables in lambda functions is you use exec:

>>> a = lambda: exec('global x; x = 1')
>>>a()
>>>x
1

You can just pass your lambda an argument which passes it along to another argument if you wish:

>>> b = lambda x: 3 + 2*x
>>> a = lambda y: y * b(y)
>>> a(1)
5
>>> a(2)
14

You can create 2 different lambda functions and pass one to the other. For example,

b = lambda x: 3+2*x
a = lambda y: [my math here using variable b(y)]

I've cooked up this recipe for python 3.8+ using PEP572 Assignment Expressions to assign arbitrary variables and execute arbitrary expressions.

# python 3.8b1
lambda a: (
    (bool(b:=a**2) or 1)
    and (bool(c:=a-b) or 1)
    and not print(f'compute: {a} + {b} + {c}')
    and (
        (ret:=a + b + c) or ret)
    )
)
tst(0) 
# prints: "compute: 0 + 0 + 0"; returns: 0
tst(1)
# prints: "compute: 1 + 1 + 0"; returns: 2
tst(8)
# prints: "compute: 8 + 64 + -56"; returns: 16

So the pattern is:

lambda: [*vars]: (
    (bool(a:=[expr(*vars)]) or 1)
    and (bool([expr]) or 1)
    and bool([always true expr])
    and not bool([always false expr])
    and (
        # parentheses required so `result:=` doesn't capture the `or result` part
        (result:=[result expr]) or result
    )
)

This may be simplified if you know the truthiness of any particular expression.

That being said, if you want to assign a variable to reuse inside a lambda, you probably should consider writing a normal function.

Im no expert at this, but the way i did it was by modifying globals() or locals() like this:

lambda: globals().__setitem__('some_variable', 'some value')

or if it's inside a function:

lambda: locals().__setitem__('some_variable', 'some value')

you could also use update() instead of __setitem__() if you wanted to, but that's a bit redundant.

You can instead use a bit of creativity, for example if you want to do some evaluation to an equation and assign the result to a variable it can be done like this:

class Results:
    res = 0

clas= Results()
setattr(clas, 'res', 3+2*4)
print(clas.res)

You could rewrite this in a oop way, like this, maybe you are using an oop structure anyways so you could integrate it in there.

class example:
     def __init__(self):
         self.a = None

 object = example()
 a = lambda n:(setattr(object, "a", 3+2*n)) #[my math here]
 a(2)
 print(object.a)

Output:

7

i hope that after 4 years my late answer will be useful

Python has setattr function to set attribute of given object. You can use it in your lambda expression.

setattr is useful when you want to programmatically-correctly (sorry) set some class or class' instance. It is not used frequently because it is easier to assign variables directly with = expression. But for lambdas... It is a salvation.

Also, iterables that support settign item (such as list), you can use <iter>.__setitem__ .

Option 1 . If you know the name of variable you're assigning.

x = lambda nameofvar, value: setattr(__builtins__, nameofvar, value)

# abc does not exist right now. Assigning and setting it to 10
x('abc', 10)
print(abc) # output: 10

alt , if you want to set object's attribute:

class MyClass:
    my_attr = False
    def __init__(self, value):
        self.value = value
myinstance = MyClass(25)

x = lambda obj, nameofvar, value: setattr(obj, nameofvar, value)
short_x = lambda nameofvar, value: setattr(MyClass, nameofvar, value)
# ^^^ this one works only for MyClass' attributes.

print(MyClass.my_attr) # output: False
x(MyClass, 'my_attr', True) # Changing MyClass' my_attr's value
print(MyClass.my_attr) # output: True
x(MyClass, 'my_attr2', 5) # Assigning new attribute to MyClass
print(MyClass.my_attr2) # output: 5
short_x('my_attr2', 123) # Setting MyClass' my_attr2 to 123
print(MyClass.my_attr2) # output: 123

print(myinstance.value) # output: 25
x(myinstance, 'value', 500)
print(myinstance.value) # output: 500

Option 2 . Make a custom class and turn variable into its instance.

class Value:
    def __init__(self, value):
        self.value = value

x = lambda var, newvalue: setattr(var, 'value', newvalue)

a = Value(15)
print(a.value) # output: 15
x(a, 25)
print(a.value) # output: 25

Option 3 . To set object's item.

lst = [15, 30, 45, 60, 75, 90]

x = lambda iterable, item, value: iterable.__setitem__(item, value)

print(lst) # output: [15, 30, 45, 60, 75, 90]
x(lst, 2, 1000)
print(lst) # output: [15, 30, 1000, 60, 75, 90]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM