Python 中的 lambda 表达式内部赋值 [英] Assignment inside lambda expression in Python
问题描述
我有一个对象列表,我想使用 filter
和 lambda
表达式删除除一个之外的所有空对象.
例如如果输入是:
[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
不能在 lambda
s 中使用.
有一个解决方法(见下文),但是当我们讨论这个主题时......
<小时>在某些情况下,您可以使用它在 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 def
s, but nonlocal
can't be used inside lambda
s.
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屋!