简体   繁体   English

您可以在 lambda 中分配变量吗?

[英]Can you assign variables in a lambda?

I was using a lambda statement to perform math, and happened to repeatedly use one certain value.我正在使用lambda语句来执行数学运算,并且碰巧重复使用了一个特定值。 Therefore I was wondering if it was possible to assign and use a variable within a lambda statement.因此,我想知道是否可以在lambda语句中分配和使用变量。

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中只允许使用表达式:

 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.但是,您可以在lambda定义第二个lambda ,并立即使用您想要的参数调用它。 (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.当然,外部和内部 lambda 都可以有多个参数,即您可以一次定义多个“变量”。 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 ).这种方法相对于例如在第一个之外定义第二个 lambda 的好处是,您仍然可以使用原始参数(如果您使用预先计算的b调用a则不可能)并且您必须为b进行计算只有一次(除了重复调用一个函数来计算 a 中a b )。


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:此外,受链接问题的最佳答案的启发,您还可以将一个或多个变量定义为 lambda 中列表理解或生成器的一部分,然后从该生成器或列表中获取next (第一个也是唯一一个)结果:

>>> 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.但是,我认为 lambda-in-a-lambda 背后的意图更加清晰。 Finally, keep in mind that instead of a one-line lambda , you could also just use a much clearer three-line def statement...最后,请记住,除了单行lambda ,您还可以使用更清晰的三行def语句...


Also, starting with Python 3.8, there will be assignment expressions , which should make it possible to write something like this.此外,从 Python 3.8 开始,将会有赋值表达式,这应该可以编写这样的东西。 (Tested with Python 3.8.10.) (使用 Python 3.8.10 测试。)

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

You can assign variables in lambda functions is you use exec:如果您使用 exec,您可以在 lambda 函数中分配变量:

>>> 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:如果您愿意,您可以将您的 lambda 参数传递给另一个参数:

>>> 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.您可以创建 2 个不同的 lambda 函数并将一个传递给另一个。 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.我已经使用 PEP572 赋值表达式为 python 3.8+ 制作了这个配方来分配任意变量并执行任意表达式。

# 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.话虽如此,如果您想分配一个变量以在 lambda 中重用,您可能应该考虑编写一个普通函数。

Im no expert at this, but the way i did it was by modifying globals() or locals() like this:我不是这方面的专家,但我这样做的方式是像这样修改globals()locals()

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.如果你愿意,你也可以使用update()而不是__setitem__() ,但这有点多余。

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.你可以用 oop 的方式重写它,就像这样,也许你无论如何都在使用 oop 结构,所以你可以将它集成到那里。

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 7

i hope that after 4 years my late answer will be useful我希望4年后我迟到的答案会有用

Python has setattr function to set attribute of given object. Python 有setattr函数来设置给定对象的属性。 You can use it in your lambda expression.您可以在 lambda 表达式中使用它。

setattr is useful when you want to programmatically-correctly (sorry) set some class or class' instance.当您想以编程方式正确(抱歉)设置某个类或类的实例时, setattr很有用。 It is not used frequently because it is easier to assign variables directly with = expression.它不经常使用,因为用=表达式直接分配变量更容易。 But for lambdas... It is a salvation.但是对于 lambdas... 这是一种救赎。

Also, iterables that support settign item (such as list), you can use <iter>.__setitem__ .此外,支持 settign 项的迭代(例如列表),您可以使用<iter>.__setitem__

Option 1 .选项 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: alt ,如果要设置对象的属性:

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 .选项 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 .选项 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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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