L'opérateur d'expression d'affectation :=
ajouté dans Python 3.8 prend en charge l'affectation à l'intérieur des expressions lambda. Cet opérateur ne peut apparaître que dans une expression (...)
entre parenthèses , entre crochets [...]
ou accolades {...}
pour des raisons syntaxiques. Par exemple, nous pourrons écrire ce qui suit:
import sys
say_hello = lambda: (
message := "Hello world",
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Dans Python 2, il était possible d'effectuer des affectations locales comme effet secondaire de la compréhension de liste.
import sys
say_hello = lambda: (
[None for message in ["Hello world"]],
sys.stdout.write(message + "\n")
)[-1]
say_hello()
Cependant, il n'est pas possible d'utiliser l'un ou l'autre de ces éléments dans votre exemple car votre variable se flag
trouve dans une portée externe et non dans la lambda
portée de. Cela n'a pas à voir avec lambda
, c'est le comportement général de Python 2. Python 3 vous permet de contourner cela avec le nonlocal
mot - clé à l'intérieur de def
s, mais nonlocal
ne peut pas être utilisé dans lambda
s.
Il y a une solution de contournement (voir ci-dessous), mais pendant que nous sommes sur le sujet ...
Dans certains cas, vous pouvez utiliser ceci pour tout faire à l'intérieur d'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 cylindre d'un rayon de 10,0 cm et d'une hauteur de 20,0 cm a un volume de 6283,2 cm³.
Un cylindre d'un rayon de 20,0 cm et d'une hauteur de 40,0 cm a un volume de 50265,5 cm³.
Un cylindre d'un rayon de 30,0cm et d'une hauteur de 60,0cm a un volume de 169646,0cm³.
Veuillez ne pas le faire.
... retour à votre exemple d'origine: bien que vous ne puissiez pas effectuer de tâches flag
variable dans la portée externe, vous pouvez utiliser des fonctions pour modifier la valeur précédemment attribuée.
Par exemple, flag
pourrait être un objet dont .value
nous définissons en utilisant 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 nous voulions adapter le thème ci-dessus, nous pourrions utiliser une compréhension de liste au lieu de setattr
:
[None for flag.value in [bool(o.name)]]
Mais vraiment, dans un code sérieux, vous devriez toujours utiliser une définition de fonction régulière au lieu d'une lambda
si vous allez faire une affectation externe.
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)