Mi sono imbattuto in un comportamento in python che ho difficoltà a capire. Questo è il codice proof-of-concept:Comportamento lambda strano nei loop
from functools import partial
if __name__ == '__main__':
sequence = ['foo', 'bar', 'spam']
loop_one = lambda seq: [lambda: el for el in seq]
no_op = lambda x: x
loop_two = lambda seq: [partial(no_op, el) for el in seq]
for func in (loop_one, loop_two):
print [f() for f in func(sequence)]
L'uscita di quanto sopra è:
['spam', 'spam', 'spam']
['foo', 'bar', 'spam']
Il comportamento di loop_one
è sorprendente per me come mi sarei aspettato che a comportarsi come loop_two
: el
è un valore immutabile (una stringa) che cambia ad ogni ciclo, ma lambda
sembra memorizzare un puntatore alla "variabile di loop", come se il ciclo ricicli lo stesso indirizzo di memoria per ciascun elemento della sequenza.
Il comportamento sopra riportato è lo stesso con le funzioni complete con un ciclo for in esse (quindi non è una sintassi di tipo list-comprehension).
Ma aspetta: c'è di più ... e più sconcertante!
Il seguente script funziona come loop_one
:
b = []
for foo in ("foo", "bar"):
b.append(lambda: foo)
print [a() for a in b]
(uscita: ['bar', 'bar']
)
Ma guarda cosa succede quando uno sostituiamo il nome della variabile foo
con a
:
b = []
for a in ("foo", "bar"):
b.append(lambda: a)
print [a() for a in b]
(uscita: [<function <lambda> at 0x25cce60>, <function <lambda> at 0x25cced8>]
)
Qualche idea di cosa sta succedendo qui? Sospetto che ci debba essere qualche trucco legato all'implementazione C sottostante del mio interprete, ma non ho nient'altro (Jthon, PyPy o simili) per verificare se questo comportamento è coerente tra diverse implementazioni.