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__
.
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
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
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.