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