lambda y fijar argumentos y nested_scopes

Chema Cortés py en ch3m4.org
Mar Mayo 4 11:12:44 CEST 2004


El Lunes, 3 de Mayo de 2004 21:23, Ernesto Revilla escribió:

> creo que Chema nos comentó alguna vez cómo se puede fijar argumentos
> para funciones.

No recuerdo bien qué dije, pero lo negaré en ausencia de mi abogado :-P


> Tengo la siguiente metaclase que crea getters y setters 
> para los attributos especificados con _attributes para cualquier clase.
>
> class Metaclase(type):
>     def __init__(self, name, bases, dic):
>         type.__init__(self, name, bases, dic)
>         if "_attributes" in dic:
>             for attr in dic['_attributes']:
>                 # crear getter y hacerlo accesible como getAtributo
>                 f=lambda s, _a=attr: getattr(s,_a)  # ???
>                 # crear setter y hacerlo accesible como setAtributo
>                 setattr(self, 'get'+attr.capitalize(), f)  # hacer
> accesible como getAtributo
>                 f=lambda s, value, _a=attr: setattr(s,_a,value) # ???
>                 setattr(self, 'set'+attr.capitalize(), f)
>
> class A(object):
>     __metaclass__=Metaclase
>     _attributes=["nombre","apellidos"]
> # se crea getNombre/setNombre y getApellidos/setApellidos
>
>
> a=A()
> a.setNombre("Pepe")
> a.setApellidos("Molina")
>
> print a.getNombre(),a.getApellidos()
>
> En las lineas marcadas con ??? se utiliza un lambda para crear la
> función de acceso al dato. He pasado explícitamente el nombre del
> atributo como segundo argumento a lambda como en:
>     f = lambda s, a_=....
> ya que si no lo hago de esta manera, aunque use los nested_scopes, el
> argumento no se evalua hasta que se evalúa el cuerpo de lambda, de
> manera que en:
>     f=lambda s: getattr(s,attr)  # ???
> attr no se evalúa hasta que de ejecute la función, con lo que siempre
> apuntará a 'apellidos'.
>
> ¿Eso es así, o hay otra manera de preevaluar una expresión para usarlo
> dentro de lambda?

Ya sabrás que existe entre los pytonisos una tremenda fobia a los scopes de 
las funciones lambda. Lo mejor que puedes hacer es utilizar métodos de la 
metaclase para definir los atributos. Mira qué te parece así el código:

class Metaclase(type):
    def __init__(self, name, bases, dic):
        type.__init__(self, name, bases, dic)
        if "_attributes" in dic:
            for attr in dic['_attributes']:
                self.mkDescriptor(attr)

    def mkDescriptor(self,attr):
        def getAttr(s): return getattr(self,attr)
        def setAttr(s,v): setattr(self,attr,v)

        setattr(self,'get'+attr.capitalize(),getAttr)
        setattr(self,'set'+attr.capitalize(),setAttr)


class A(object):
    __metaclass__=Metaclase
    _attributes=["nombre","apellidos"]

a=A()
a.setNombre("Pepe")
a.setApellidos("Molina")

print a.getNombre(),a.getApellidos()


> ¿sería poco recomendable usar una cadena de caracteres y eval para crear
> esas funciones?

Creo que esto es lo que preguntas en el siguiente mensaje.




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