closures
Chema Cortes
pych3m4 en gmail.com
Lun Jul 23 05:47:14 CEST 2007
El 22/07/07, Carles Pina i Estany <carles en pina.cat> escribió:
> Estoy intentando entender las closures. En la Wikipedia (http://en.wikipedia.org/wiki/Closure_(computer_science) (al principio) puedo ver de
> qué se trata. Entiendo que es que el comportamiento de una función está
> determinado, en parte, por el comportamiento de datos/código externo de
> esta función. Básicamente, que puede acceder fuera de la función.
Umm! Dicho así parece otra cosa de lo que es. Una función nunca
debería acceder "fuera" de sus dominios bajo ninguna circunstancia.
Normalmente, las funciones se definen en el mismo entorno donde se
ejecutan; pero hay ocasiones en las que no ocurre así, como en el caso
de las funciones anidadas donde una función se define dentro del
entorno local de otra. En este caso, la función anidada se ejecutará
en el entorno donde se ha definido, fuera de los ojos del resto del
programa. Ésto es lo que se conoce por "clausura".
Así, podemos definir "clausura" como el entorno donde se define una
función y que sólo va a ser "visible" por esta función. Y por
"entorno", en python, debería entenderse el conjunto de objetos de los
que contamos con alguna "referencia" a ellos (en otros lenguajes se
hablan de otras cosas como stacks, heaps, etc).
> Leo aquí (ojo, del año 2003):
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/67618
> Que python no tiene closures completas como Ruby por este motivo:
> -----
> But in Python, the inner function only has access to the _object_, not
> to the original variable which refers to the object
> -----
>
> Así, en Python hay closures "parciales"? He entendido bien que las
> clsorues son algo tan simple como que una función pueda acceder a datos
> de fuera de la función, de quien llama la función?
¡ÉSO ES PECADO!
LLámalas, si quieres, clausuras "parciales"; pero, al fin y al cabo,
son clausuras. No siempre es buena idea permitir que las funciones
anidadas alteren variables que no sean suyas.
¿Qué problema hay en encapsular la función, junto a las variable a las
que accede dentro de una clase (function wrapper)?
def make_counter(start):
class counter:
def __init__(self,start):
self._start=start
def __call__(self,inc):
self._start+=inc
return self._start
return counter(start)
c=make_counter(0)
print c(3)
print c(2)
Y si no, con generadores e iteradores seguro que también iría bien.
def make_counter2(start):
while True:
inc=(yield start)
if inc is not None:
start+=inc
c=make_counter2(0)
c.next()
print c.send(3)
print c.send(2)
Una versión "forzada", que viene a emular lo que se entendería por
clausura "completa":
def make_counter(start):
def counter(inc):
global start
start+=inc
return start
counter.func_globals.clear()
counter.func_globals.update(locals())
return counter
c=make_counter(0)
print c(3)
print c(2)
Una versión más moderada que usa atributos de función:
def make_counter(start):
def counter(inc):
f.start+=inc
return f.start
f.start=start
return counter
Y la versión de libro:
def make_counter(start):
s=[start]
def counter(inc):
s[0]+=inc
return s[0]
return counter
Más información sobre la lista de distribución Python-es