Оператор вираження присвоєння, :=доданий у 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слово за допомогою ключового слова всередині defs, але 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()])()
Циліндр із радіусом 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)