C’e una differenza sottile tra le lambda di C#,python, ruby, lisp, ml etc.. Tutti offrono in modo differente la possibilità di creare delle funzioni (anonime o meno) e di passarle in giro come normali oggetti.
La definizione di vere chiusure lessicali e’ ambigua, quindi non si può dire che un meccanismo sia meglio di un altro, ma possiamo vedere le differenze tra come funzionano le clsoure in ruby ed in python.
Una funzione anonima in python si crea con un’espressione introdotta dalla keyword lambda. Poiché python prevede una divisione tra statement ed expression, ed è impossibile usare uno statement all’interno di un’espressione, non si può usare l’assegnazione all’interno di una lambda expression:
(l’esempio è lo stesso visto in Forma Lambda)
>>> def esponenziale(n): ... lambda a: n=n*n ... File "<stdin>", line 2 SyntaxError: can't assign to lambda
è possibile però definire funzioni annidate in python, ottenendo sostanzialmente lo stesso risultato di una lambda ma potendo usare statement:
>>> def square_generator(num): ... def f(): ... return num * num ... return f ... >>> square2=square_generator(2) >>> square2() 4
Come vedete python riesce a trovare la variabile num vedetenello pythonscope riesceesterno. Se però proviamo a trovarefare la variabilestessa @num@cosa nelloche scopeabbiamo esterno.fatto Sein peròruby proviamootteniamo aun fare la stessa cosa che abbiamo fatto in ruby otteniamo un errore:
<pre>errore:
>>> def exp(num): ... def f(): ... num= num * num ... return num ... return f ... >>> potenze=exp(2) >>> potenze() Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 3, in f UnboundLocalError: local variable 'num' referenced before assignment</pre>
Infatti python al momento dell’assegnazione non assegnerà alla variabile nello scope di exp, ma ne creerà una nello scope della funzione interna f. Quando poi si cercherà di accedere alla variabile num per moltiplicarla con se stessa python troverà una variabile nello scope locale, ma per lui si tratterà di una variabile a cui non è stato ancora assegnato un valore e quindi solleverà un’eccezione.
>>> def exp(num): ... ary=[num] ... def f(): ... ary[0]= ary[0]**2 ... return ary[0] ... return f ... >>> square=exp(2) >>> square() 4 >>> square() 16