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 flag
está em um escopo externo, não o lambda
escopo de. Isso não tem a ver com lambda
, é o comportamento geral em Python 2. Python 3 permite que você contorne isso com a nonlocal
palavra - chave dentro dedef
s, mas nonlocal
não pode ser usada dentro de lambda
s.
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 à flag
variável no escopo externo, você pode usar funções para modificar o valor atribuído anteriormente.
Por exemplo, flag
poderia ser um objeto cujo .value
definimos 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 lambda
se 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)