Closure in python

Vedi tutte le pagine e le modifiche recenti o scarica i sorgenti nella pagina


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 nello scope esterno. Se però proviamo a fare la stessa cosa che abbiamo fatto in ruby otteniamo un 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

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.

E’ possibile ottenere lo stesso risultato che si ottiene in ruby usando un’oggetto mutabile:
>>> def exp(num):
...  ary=[num]
...  def f():
...   ary[0]= ary[0]**2
...   return ary[0]
...  return f
...
>>> square=exp(2)
>>> square()
4
>>> square()
16
Updated on February 19, 2006 18:04 by gabriele renzi (151.42.217.247)