Python 中的 lambda 表达式内部赋值 [英] Assignment inside lambda expression in Python

查看:39
本文介绍了Python 中的 lambda 表达式内部赋值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对象列表,我想使用 filterlambda 表达式删除除一个之外的所有空对象.

例如如果输入是:

[Object(name=""), Object(name="fake_name"), Object(name="")]

...那么输出应该是:

[Object(name=""), Object(name="fake_name")]

有没有办法给 lambda 表达式添加赋值?例如:

flag = True输入 = [对象(名称 ="),对象(名称 =假名"),对象(名称 =")]输出 = 过滤器((lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),输入)

解决方案

赋值表达式Python 3.8 中添加的运算符 := 支持 lambda 表达式内部的赋值.此运算符只能出现在带括号的 (...)、带括号的 [...] 或带括号的 {...} 表达式中出于语法原因.例如,我们将能够编写以下内容:

import syssay_hello = lambda: (消息:=你好世界",sys.stdout.write(message + "
"))[-1]问好()

在 Python 2 中,作为列表推导式的副作用,可以执行局部赋值.

import syssay_hello = lambda: ([无 ["Hello world"]] 中的消息,sys.stdout.write(message + "
"))[-1]问好()

但是,在您的示例中无法使用其中任何一个,因为您的变量 flag 位于外部范围内,而不是 lambda 的范围内.这与 lambda 无关,它是 Python 2 中的一般行为.Python 3 允许您使用 def<中的 nonlocal 关键字来解决这个问题./code>s,但 nonlocal 不能在 lambdas 中使用.

有一个解决方法(见下文),但是当我们讨论这个主题时......

<小时>

在某些情况下,您可以使用它在 lambda 中执行所有操作:

(lambda: [['定义'对于 [__import__('sys')] 中的 sys对于 [__import__('math')] 中的数学对于 [lambda *vals: None] 中的 sub在 [lambda *vals: vals[-1]] 中找点乐子对于 [lambda *vals: sub(sys.stdout.write(u" ".join(map(unicode, vals)) + u"
"))]对于 [type('Cylinder', (object,), dict(__init__ = lambda 自我,半径,高度:子(setattr(自我,'半径',半径),setattr(self, '高度', 高度)),体积 = 属性(lambda 自我:乐趣(['def' for top_area in [math.pi * self.radius ** 2]],self.height * top_area))))]对于 [lambda: sub(['loop' for factor in [1, 2, 3] if sub(['定义'对于 my_radius, my_height 在 [[10 * factor, 20 * factor]]对于 [Cylinder(my_radius, my_height)]] 中的 my_圆筒,echo(u"半径为 %.1fcm 的圆柱体,高度为"u%.1fcm 的体积为 %.1fcm³."% (my_radius, my_height, my_圆柱体.volume)))])]],主要的()])()

<块引用>

半径为 10.0cm,高为 20.0cm 的圆柱体的体积为 6283.2cm³.
一个半径为 20.0cm,高为 40.0cm 的圆柱体,其体积为 50265.5cm³.
一个半径为30.0cm,高为60.0cm的圆柱体,其体积为169646.0cm³.

请不要.

<小时>

...回到你原来的例子:虽然你不能在外部作用域中对 flag 变量执行赋值,但你可以使用函数来修改之前赋值的值.

例如,flag 可以是我们使用 setattr:

flag = Object(value=True)输入 = [对象(名称=''),对象(名称='假名'),对象(名称='')]输出 = 过滤器(拉姆达 o: [flag.value 或 bool(o.name),setattr(flag, 'value', flag.value and bool(o.name))][0],输入)

[Object(name=''), Object(name='fake_name')]

如果我们想适应上面的主题,我们可以使用列表推导而不是 setattr:

 [[bool(o.name)] 中的 flag.value 无]]

<小时>

但实际上,在严肃的代码中,如果您要进行外部赋值,您应该始终使用常规函数定义而不是 lambda.

flag = Object(value=True)def not_empty_except_first(o):结果 = flag.value 或 bool(o.name)flag.value = flag.value 和 bool(o.name)返回结果输入 = [对象(名称 ="),对象(名称 =假名"),对象(名称 =")]输出 = 过滤器(not_empty_except_first,输入)

I have a list of objects and I want to remove all objects that are empty except for one, using filter and a lambda expression.

For example if the input is:

[Object(name=""), Object(name="fake_name"), Object(name="")]

...then the output should be:

[Object(name=""), Object(name="fake_name")]

Is there a way to add an assignment to a lambda expression? For example:

flag = True 
input = [Object(name=""), Object(name="fake_name"), Object(name="")] 
output = filter(
    (lambda o: [flag or bool(o.name), flag = flag and bool(o.name)][0]),
    input
)

解决方案

The assignment expression operator := added in Python 3.8 supports assignment inside of lambda expressions. This operator can only appear within a parenthesized (...), bracketed [...], or braced {...} expression for syntactic reasons. For example, we will be able to write the following:

import sys
say_hello = lambda: (
    message := "Hello world",
    sys.stdout.write(message + "
")
)[-1]
say_hello()

In Python 2, it was possible to perform local assignments as a side effect of list comprehensions.

import sys
say_hello = lambda: (
    [None for message in ["Hello world"]],
    sys.stdout.write(message + "
")
)[-1]
say_hello()

However, it's not possible to use either of these in your example because your variable flag is in an outer scope, not the lambda's scope. This doesn't have to do with lambda, it's the general behaviour in Python 2. Python 3 lets you get around this with the nonlocal keyword inside of defs, but nonlocal can't be used inside lambdas.

There's a workaround (see below), but while we're on the topic...


In some cases you can use this to do everything inside of a lambda:

(lambda: [
    ['def'
        for sys in [__import__('sys')]
        for math in [__import__('math')]

        for sub in [lambda *vals: None]
        for fun in [lambda *vals: vals[-1]]

        for echo in [lambda *vals: sub(
            sys.stdout.write(u" ".join(map(unicode, vals)) + u"
"))]

        for Cylinder in [type('Cylinder', (object,), dict(
            __init__ = lambda self, radius, height: sub(
                setattr(self, 'radius', radius),
                setattr(self, 'height', height)),

            volume = property(lambda self: fun(
                ['def' for top_area in [math.pi * self.radius ** 2]],

                self.height * top_area))))]

        for main in [lambda: sub(
            ['loop' for factor in [1, 2, 3] if sub(
                ['def'
                    for my_radius, my_height in [[10 * factor, 20 * factor]]
                    for my_cylinder in [Cylinder(my_radius, my_height)]],

                echo(u"A cylinder with a radius of %.1fcm and a height "
                     u"of %.1fcm has a volume of %.1fcm³."
                     % (my_radius, my_height, my_cylinder.volume)))])]],

    main()])()

A cylinder with a radius of 10.0cm and a height of 20.0cm has a volume of 6283.2cm³.
A cylinder with a radius of 20.0cm and a height of 40.0cm has a volume of 50265.5cm³.
A cylinder with a radius of 30.0cm and a height of 60.0cm has a volume of 169646.0cm³.

Please don't.


...back to your original example: though you can't perform assignments to the flag variable in the outer scope, you can use functions to modify the previously-assigned value.

For example, flag could be an object whose .value we set using setattr:

flag = Object(value=True)
input = [Object(name=''), Object(name='fake_name'), Object(name='')] 
output = filter(lambda o: [
    flag.value or bool(o.name),
    setattr(flag, 'value', flag.value and bool(o.name))
][0], input)

[Object(name=''), Object(name='fake_name')]

If we wanted to fit the above theme, we could use a list comprehension instead of setattr:

    [None for flag.value in [bool(o.name)]]


But really, in serious code you should always use a regular function definition instead of a lambda if you're going to be doing outer assignment.

flag = Object(value=True)
def not_empty_except_first(o):
    result = flag.value or bool(o.name)
    flag.value = flag.value and bool(o.name)
    return result
input = [Object(name=""), Object(name="fake_name"), Object(name="")] 
output = filter(not_empty_except_first, input)

这篇关于Python 中的 lambda 表达式内部赋值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆