Оператор выражения присваивания, :=
добавленный в Python 3.8, поддерживает присваивание внутри лямбда-выражений. Этот оператор может появляться только в скобках (...)
, скобках [...]
или {...}
выражениях в скобках по синтаксическим причинам. Например, мы сможем написать следующее:
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 позволяет обойти это с помощью nonlocal
ключевого слова внутри def
s, но nonlocal
не может использоваться внутриlambda
s.
Есть обходной путь (см. Ниже), но пока мы обсуждаем эту тему ...
В некоторых случаях вы можете использовать это, чтобы делать все внутри 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()])()
Цилиндр с радиусом 10,0 см и высотой 20,0 см имеет объем 6283,2 см³.
Цилиндр с радиусом 20,0 см и высотой 40,0 см имеет объем 50265,5 см³.
Цилиндр с радиусом 30,0 см и высотой 60,0 см имеет объем 169646,0 см³.
Пожалуйста, не надо.
... вернемся к исходному примеру: хотя вы не можете выполнять назначения для flag
переменной во внешней области видимости, вы можете использовать функции для изменения ранее присвоенного значения.
Например, это flag
может быть объект, который .value
мы установили с помощью 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')]
Если бы мы хотели соответствовать указанной выше теме, мы могли бы использовать понимание списка вместо setattr
:
[None for flag.value in [bool(o.name)]]
Но на самом деле в серьезном коде вы всегда должны использовать обычное определение функции вместо a, 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)