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 flagin einem äußeren Bereich befindet, nicht im lambdaBereich des. Dies hat nichts mit lambdadem allgemeinen Verhalten in Python 2 zu tun. Mit Python 3 können Sie dies mit dem nonlocalSchlüsselwort in defs umgehen, nonlocalkönnen jedoch nicht in lambdas 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 flagVariablen im äußeren Bereich keine Zuweisungen vornehmen können, können Sie den zuvor zugewiesenen Wert mithilfe von Funktionen ändern.
Zum Beispiel flagkönnte ein Objekt sein, dessen .valuewir 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, lambdawenn 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)