Metaclases, crear funciones a partir de plantillas de texto

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


El Lunes, 3 de Mayo de 2004 21:54, Ernesto Revilla escribió:
> Hola de nuevo,
>
> cómo se crearían nuevas funciones a partir de plantillas de texto desde
> Metaclases? Sólo he encontrado la siguiente manera:
>
> class Metaclase2(type):
>     def __init__(self, name, bases, dic):
>         type.__init__(self, name, bases, dic)
>         if "_attributes" in dic:
>             ns={} # creo un espacio de nombre privado donde se van a
> crear las funciones
>             for attr in dic['_attributes']:
>                 # crear getter y hacerlo accesible como getAtributo
>                 capAttr=attr.capitalize()
>                 getterName,setterName="get"+capAttr,"set"+capAttr
>                 exec("def %s(self): return self._%s" %
> (getterName,attr),ns,ns)
>                 exec("def %s(self, value): self._%s=value" %
> (setterName,attr),ns,ns)
>                 getter,setter=ns[getterName],ns[setterName] # recupero
> las funciones creadas
>                 setattr(self, getterName, getter) # lo hago disponible
>                 setattr(self, setterName, setter)
>
> class B(object):
>     __metaclass__=Metaclase2
>     _attributes=["nombre","apellidos"]
>
> b=B()
> b.setNombre("Erny")
> b.setApellidos("Revilla")
> print b.getNombre(),b.getApellidos()
>
> # hay una manera más breve de hacerlo, es decir, crearlos directamente
> en el mismo espacio de nombres? al menos, a mi no me funciona, indicando
> 'dic' como espacio de nombres.

Empleando __new__ en lugar de __init__ en la metaclase. Una vez que está 
creada la clase, sus atributos son de sólo lectura. Por eso hay que modificar 
el diccionario antes de la creación de la clase:

class Metaclase2(type):
    def __new__(self, name, bases, dic):
        if "_attributes" in dic:
            for attr in dic['_attributes']:
                # crear getter y hacerlo accesible como getAtributo
                capAttr=attr.capitalize()
                getterName,setterName="get"+capAttr,"set"+capAttr
                exec("def %s(self): return self._%s" % (getterName,attr),dic)
                exec("def %s(self, value): self._%s=value" % 
(setterName,attr),dic)
        return type.__new__(self, name, bases, dic)

class B(object):
    __metaclass__=Metaclase2
    _attributes=["nombre","apellidos"]

b=B()
b.setNombre("Erny")
b.setApellidos("Revilla")
print b.getNombre(),b.getApellidos()




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