Python中lambda表达式内的赋值

2024-04-25 10:01:24 发布

您现在位置:Python中文网/ 问答频道 /正文

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

例如,如果输入是:

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

…那么输出应该是:

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

是否有方法向lambda表达式添加赋值?例如:

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
)

Tags: 对象方法lambdanametrue列表inputoutput
3条回答

不能在filter/lambda表达式中真正维护状态(除非滥用全局命名空间)。但是,您可以使用在reduce()表达式中传递的累积结果来实现类似的功能:

>>> f = lambda a, b: (a.append(b) or a) if (b not in a) else a
>>> input = ["foo", u"", "bar", "", "", "x"]
>>> reduce(f, input, [])
['foo', u'', 'bar', 'x']
>>> 

当然,你可以稍微调整一下。在这种情况下,它过滤掉重复项,但是您也可以使用a.count(""),例如,仅限制空字符串。

不用说,你可以这么做,但你真的不应该这样做

最后,您可以用纯Python做任何事情lambdahttp://vanderwijk.info/blog/pure-lambda-calculus-python/

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

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

在Python 2中,作为列表理解的副作用,可以执行本地赋值。

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

但是,在您的示例中不可能使用这两种方法,因为变量flag位于外部作用域中,而不是lambda的作用域中。这与lambda无关,这是Python 2中的一般行为。Python 3允许您在defs内部使用nonlocal关键字来解决这个问题,但是nonlocal不能在lambdas内部使用

有一个解决办法(见下文),但当我们讨论这个话题时。。。


在某些情况下,您可以使用它来执行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"\n"))]

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

请不要


…回到原来的示例:虽然不能对外部作用域中的flag变量执行赋值,但可以使用函数修改先前赋值。

例如,flag可以是我们使用^{}设置其.value的对象:

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')]

如果我们想符合上述主题,可以使用列表理解而不是setattr

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

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

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)

当您可以移除所有空值时,不需要使用lambda,如果输入大小发生变化,则可以放回lambda:

input = [Object(name=""), Object(name="fake_name"), Object(name="")] 
output = [x for x in input if x.name]
if(len(input) != len(output)):
    output.append(Object(name=""))

相关问题 更多 >