Binding de las variables libres de funciones

Arnau Sanchez pyarnau en gmail.com
Vie Nov 7 11:31:16 CET 2008


German Kruszewski escribió:

> La manera de hacerlo que se me ocurrió fue la siguiente:
> class C:
>     def __init__(self):
>         for i in range(1,3):
>             def f():
>                 print "Esta es la funcion %i" % i
>             setattr(self, 'f' + str(i), f)
> 
> c = C()
> c.f1()
> c.f2()

Antes de nada, apuntar que con eso estás añadiendo una función a la instancia, 
no un método, que muy probablemente es lo que necesites. En Python esto último 
se suele hacer con new.instancemethod(). Cierto es que "self" queda en la 
clausura de "f" y por tanto puedes acceder igualmente a la instancia, pero 
parece más lógico añadirlo explícitamente como método.

> Sin embargo, como mencioné antes, no puedo cambiar la aridad de la función.
> ¿Alguien sabe cómo podría solucionar el problema de generar automáticamente
> estas funciones sin agregar parámetros extra?

Lo estándar en estos casos es recubrir la función en cuestión con otra función 
que cargue con los parámetros que no queremos. Asumiendo que, según lo comentado 
antes, lo que pretendemos es añadir un método, el código podría quedar:

import new

class C:
     def __init__(self):
         self.k = "k"
         for i in range(1, 3):
             def f0(i=i):
                 def f(self):
                     print "funcion:", i, self.k
                 return new.instancemethod(f, self)
             setattr(self, 'f' + str(i), f0())

Añado un acceso a una variable de instancia (k) para comprobar que es 
efectivamente es accesible desde las funciones que creamos al vuelo.

En este punto parece lógico abstraer un poco el código, por una parte las líneas 
que añaden el método y por otra la propia función de generación de "f". Podría 
quedar así:

def add_method(instance, function, name):
     method = new.instancemethod(function, instance)
     setattr(instance, name, method)

class C:
     def _add_f(self, i):
         def f(self):
             print "funcion:", i, self.k
         add_method(self, f, 'f' + str(i))

     def __init__(self):
         self.k = 1
         for i in range(1, 3):
             self._add_f(i)

¿Funciona esto como esperas?

arnau

-- 
Web: http://www.arnau-sanchez.com
_______________________________________________
Lista de correo Python-es 
http://listas.aditel.org/listinfo/python-es
FAQ: http://listas.aditel.org/faqpyes





Más información sobre la lista de distribución Python-es