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 qu'à l'intérieur d'une expression entre parenthèses. (...)
entre parenthèses [...]
ou contreventée {...}
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 des compréhensions de listes.
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 dans votre exemple car votre variable flag
se trouve dans une portée externe, et non dans la lambda
de l'entreprise. Cela n'a rien à voir avec lambda
C'est le comportement général de Python 2. Python 3 vous permet de contourner ce problème grâce à la fonction nonlocal
à l'intérieur de def
mais nonlocal
ne peut pas être utilisé à l'intérieur lambda
s.
Il existe une solution de contournement (voir ci-dessous), mais tant que nous sommes sur le sujet...
Dans certains cas, vous pouvez l'utiliser pour tout faire à l'intérieur d'une 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 cm et d'une hauteur de 20 cm a un volume de 6283,2 cm³.
Un cylindre d'un rayon de 20 cm et d'une hauteur de 40 cm a un volume de 50265,5 cm³.
Un cylindre d'un rayon de 30 cm et d'une hauteur de 60 cm a un volume de 169646 cm³.
S'il te plaît, ne le fais pas.
...pour en revenir à votre exemple initial : bien que vous ne puissiez pas effectuer d'affectations à l'élément flag
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
que 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 respecter 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 en réalité, dans un code sérieux, vous devriez toujours utiliser une définition de fonction ordinaire au lieu d'un fichier de type lambda
si vous allez faire une mission extérieure.
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)
1 votes
Non. Mais vous n'avez pas besoin de ça. En fait, je pense que ce serait une façon assez obscure d'y parvenir, même si ça marchait.
8 votes
Pourquoi ne pas simplement passer une vieille fonction ordinaire dans le filtre ?
5 votes
Je voulais utiliser lambda juste pour que ce soit une solution vraiment compacte. Je me souviens qu'en OCaml, je pouvais enchaîner des instructions d'impression avant l'expression de retour, et j'ai pensé que cela pourrait être reproduit en Python.
0 votes
C'est assez pénible d'être dans le flux de développement d'un pipeilne enchaîné puis de réaliser : "oh je veux créer une var temp pour rendre le flux plus clair" ou "je veux loguer cette étape intermédiaire" : et ensuite vous devez sauter ailleurs pour créer une fonction pour le faire : et nom cette fonction et en garder la trace - même si elle n'est utilisée qu'à un seul endroit .