Оператор выражения присваивания :=
, добавленный в 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
с.
Есть обходной путь (см. Ниже), но пока мы находимся на теме ...
В некоторых случаях вы можете использовать это, чтобы сделать все внутри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)]]
Но на самом деле, в серьезном коде вы всегда должны использовать обычныйопределение функции вместо 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)