L'operatore di espressione di assegnazione :=
aggiunto in Python 3.8 supporta l'assegnazione all'interno di espressioni lambda. Questo operatore può essere visualizzato solo all'interno di un'espressione tra parentesi (...)
, tra parentesi [...]
o tra parentesi {...}
per motivi sintattici. Ad esempio, saremo in grado di scrivere quanto segue:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
In Python 2, era possibile eseguire assegnazioni locali come effetto collaterale della comprensione delle liste.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Tuttavia, non è possibile utilizzare nessuno di questi nel tuo esempio perché la tua variabile flag
è in un ambito esterno, non in quello di lambda
. Questo non ha a che fare con lambda
, è il comportamento generale in Python 2. Python 3 ti consente di aggirare questo problema con la nonlocal
parola chiave all'interno di def
s, ma nonlocal
non può essere usato all'internolambda
s.
C'è una soluzione alternativa (vedi sotto), ma visto che siamo in argomento ...
In alcuni casi puoi usarlo per fare tutto all'interno di un 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()])()
Un cilindro con un raggio di 10,0 cm e un'altezza di 20,0 cm ha un volume di 6283,2 cm³.
Un cilindro con un raggio di 20,0 cm e un'altezza di 40,0 cm ha un volume di 50265,5 cm³.
Un cilindro con un raggio di 30,0 cm e un'altezza di 60,0 cm ha un volume di 169646,0 cm³.
Per favore non farlo.
... tornando al tuo esempio originale: anche se non puoi eseguire compiti nel file flag
variabile nell'ambito esterno, è possibile utilizzare funzioni per modificare il valore assegnato in precedenza.
Ad esempio, flag
potrebbe essere un oggetto di cui .value
abbiamo impostato utilizzando 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')]
Se volessimo adattare il tema di cui sopra, potremmo usare una comprensione dell'elenco invece di setattr
:
[None for flag.value in [bool(o.name)]]
Ma in realtà, nel codice serio dovresti sempre usare una definizione di funzione regolare invece di una lambda
se hai intenzione di fare assegnazioni esterne.
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)