O operador de expressão de atribuição :=adicionado no Python 3.8 suporta atribuição dentro de expressões lambda. Este operador só pode aparecer entre parênteses (...), colchetes [...]ou colchetes{...} expressão por motivos sintáticos. Por exemplo, seremos capazes de escrever o seguinte:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
No Python 2, era possível realizar atribuições locais como um efeito colateral das compreensões de lista.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
No entanto, não é possível usar nenhum desses em seu exemplo porque sua variável flagestá em um escopo externo, não o lambdaescopo de. Isso não tem a ver com lambda, é o comportamento geral em Python 2. Python 3 permite que você contorne isso com a nonlocalpalavra - chave dentro dedef s, mas nonlocalnão pode ser usada dentro de lambdas.
Há uma solução alternativa (veja abaixo), mas já que estamos no assunto ...
Em alguns casos, você pode usar isso para fazer tudo dentro de 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()])()
Um cilindro com raio de 10,0cm e altura de 20,0cm tem um volume de 6283,2cm³.
Um cilindro com raio de 20,0cm e altura de 40,0cm tem um volume de 50265,5cm³.
Um cilindro com raio de 30,0cm e altura de 60,0cm tem um volume de 169646,0cm³.
Por favor, não.
... de volta ao seu exemplo original: embora você não possa realizar atribuições à flagvariável no escopo externo, você pode usar funções para modificar o valor atribuído anteriormente.
Por exemplo, flagpoderia ser um objeto cujo .valuedefinimos 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')]
Se quiséssemos nos ajustar ao tema acima, poderíamos usar uma compreensão de lista em vez de setattr:
[None for flag.value in [bool(o.name)]]
Mas, realmente, em código sério, você sempre deve usar uma definição de função regular em vez de uma lambdase for fazer atribuições externas.
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)