Der :=
in Python 3.8 hinzugefügte Zuweisungsausdrucksoperator unterstützt die Zuweisung innerhalb von Lambda-Ausdrücken. Dieser Operator kann aus syntaktischen Gründen nur in einem Ausdruck in Klammern (...)
, Klammern [...]
oder Klammern angezeigt {...}
werden. Zum Beispiel können wir Folgendes schreiben:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
In Python 2 war es möglich, lokale Zuweisungen als Nebeneffekt des Listenverständnisses durchzuführen.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
In Ihrem Beispiel ist es jedoch nicht möglich, eines dieser Elemente zu verwenden, da sich Ihre Variable flag
in einem äußeren Bereich befindet, nicht im lambda
Bereich des. Dies hat nichts mit lambda
dem allgemeinen Verhalten in Python 2 zu tun. Mit Python 3 können Sie dies mit dem nonlocal
Schlüsselwort in def
s umgehen, nonlocal
können jedoch nicht in lambda
s verwendet werden.
Es gibt eine Problemumgehung (siehe unten), aber während wir beim Thema sind ...
In einigen Fällen können Sie dies verwenden, um alles innerhalb eines 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()])()
Ein Zylinder mit einem Radius von 10,0 cm und einer Höhe von 20,0 cm hat ein Volumen von 6283,2 cm³.
Ein Zylinder mit einem Radius von 20,0 cm und einer Höhe von 40,0 cm hat ein Volumen von 50265,5 cm³.
Ein Zylinder mit einem Radius von 30,0 cm und einer Höhe von 60,0 cm hat ein Volumen von 169646,0 cm³.
Bitte nicht.
... zurück zu Ihrem ursprünglichen Beispiel: Obwohl Sie der flag
Variablen im äußeren Bereich keine Zuweisungen vornehmen können, können Sie den zuvor zugewiesenen Wert mithilfe von Funktionen ändern.
Zum Beispiel flag
könnte ein Objekt sein, dessen .value
wir setzen mit 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')]
Wenn wir das obige Thema anpassen wollten, könnten wir ein Listenverständnis verwenden, anstatt setattr
:
[None for flag.value in [bool(o.name)]]
Aber wirklich, in seriösem Code sollten Sie immer eine reguläre Funktionsdefinition anstelle einer verwenden, lambda
wenn Sie eine äußere Zuweisung vornehmen möchten.
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)