Derivacion de tipos, interceptar operaciones

Chema Cortes py en ch3m4.org
Mar Mar 18 01:20:12 CET 2008


El Monday 17 March 2008 22:03:18 Oswaldo Hernández escribió:

> Muy, muy, muy interesante, aunque no es lo mismo, se parece bastante a mi
> proyecto. Lo revisare con detenimiento.
> Sobre los slots habia visto algo, pero lo volveré a revisar.

Lo de los slots no tiene demasiada importancia. Tan sólo saber que está ahí 
por si quieres un control más fino.

Algunos consejos del código que has puesto:


> Mi necesidad es filtrar las instancias antes de que se realice cualquier
> tipo de operacion con ellas, y en ciertos casos impedir la operacion
> lanzando un ValueError.
>
> Un resumen de lo que he hecho he hecho es lo siguiente:
>
> 1.- Definicion de las clases con un metodo __new__ comun
>
> # esta funcion es llamada en el new de las bases para verificar valores y
> creacion de instancia def _Super_New_(cls, *args):
>      # verificacion de rango
>      if cls.Rango and args[0] < cls.Rango[0] or args[0] > cls.Rango[1]:

Los rangos, en python, quedan más elegantes así:

 ... and cls.Rango[1]<args[0]<cls.Rango[0]


>          raise ValueError
>      ...otros chequeos y adaptaciones ...
>
>      return = cls.__base__.__new__(cls, *args)
>
> # Clases principales
> class c_int(int):
>      Valido = True	# en ciertos casos me interesa no dar error
> 			# y marcar la instancia como 'No Valida'
>      Rango = None
>      def __new__(cls, *args):
>          return _Super_new_(cls, *args)

Mejor así:

  __new__=_Super_new_

Da más a entender que "_Super_new_" es un descriptor.


> class c_date(datetime.date):
>      Valido = True
>      Rango = None
>      def __new__(cls, *args):
>          return _Super_new_(cls, *args)

Evidentemente, necesitas "metaclases":

class M(type):
  def __new__(meta,name,base,dic):
    dic.update({
      "Valido":True,
      "Rango":None,
      "__new__":_Super_new_,
    })
    return type.__new__(meta,name,base,dic)

class c_int(int):
  __metaclass__=M

class c_date(datetime.date):
  __metaclass__=M


De manera similar, se pueden definir todos los wrappers a los métodos 
estáticos dentro de la metaclase:


Operadores = ("__add__", "__sub__", ....)

def __wrapper(op):
  def __supermethod(self, *args,**kwds):
     if not self.Valido:
         raise ValueError
     if hasattr(args[0], "Valido") and not args[0].Valido:
         raise ValueError
     return getattr(self.__base__, op)(self, *args, **kwds)
  return __supermethod

class M(type):
  def __new__(meta,name,base,dic):
    dic.update({
      "Valido":True,
      "Rango":None,
      "__new__":_Super_new_,
    })
    for op in Operadores:
      dic[op]=__wrapper(op)

    return type.__new__(meta,name,base,dic)


Lo he hecho muy rápido, así que mejor será que revises y lo ajustes a lo que 
quieres hacer. Creo que por aquí tienes por donde trabajar.


------------ próxima parte ------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part.
URL: <http://mail.python.org/pipermail/python-es/attachments/20080318/b4e78cb2/attachment.pgp>
------------ próxima parte ------------
_______________________________________________
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