El operador de expresión de asignación :=agregado en Python 3.8 admite la asignación dentro de expresiones lambda. Este operador solo puede aparecer dentro de una expresión (...)entre paréntesis , entre corchetes [...]o entre corchetes {...}por razones sintácticas. Por ejemplo, podremos escribir lo siguiente:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
En Python 2, era posible realizar asignaciones locales como efecto secundario de las listas por comprensión.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Sin embargo, no es posible usar ninguno de estos en su ejemplo porque su variable flagestá en un alcance externo, no en el lambdaalcance de. Esto no tiene que ver con lambda, es el comportamiento general en Python 2. Python 3 le permite evitar esto con la nonlocalpalabra clave dentro de defs, pero nonlocalno puede usarse dentro de lambdas.
Hay una solución alternativa (ver más abajo), pero ya que estamos en el tema ...
En algunos casos, puede usar esto para hacer todo dentro de 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 radio de 10.0cm y una altura de 20.0cm tiene un volumen de 6283.2cm³.
Un cilindro con un radio de 20,0 cm y una altura de 40,0 cm tiene un volumen de 50265,5 cm³.
Un cilindro con un radio de 30.0cm y una altura de 60.0cm tiene un volumen de 169646.0cm³.
Por favor no lo hagas.
... volviendo a su ejemplo original: aunque no puede realizar asignaciones a la flagvariable en el alcance externo, puede usar funciones para modificar el valor asignado previamente.
Por ejemplo, flagpodría ser un objeto .valueque configuramos usando 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')]
Si quisiéramos encajar en el tema anterior, podríamos usar una lista de comprensión en lugar de setattr:
[None for flag.value in [bool(o.name)]]
Pero realmente, en código serio, siempre debe usar una definición de función regular en lugar de una lambdasi va a realizar una asignación externa.
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)