Estoy intentando escribir un decorador que proporcione funcionalidad de sobrecarga de método a python, similar al mencionado en PEP 3124.Decodificador de sobrecarga de método
El decorador que escribí funciona muy bien para las funciones normales, pero no puedo hacer que funcione para los métodos en una clase.
Aquí es el decorador:
class Overload(object):
def __init__(self, default):
self.default_function = default
self.type_map = {}
self.pos = None
def __call__(self, *args, **kwargs):
print self
try:
if self.pos is None:
pos = kwargs.get("pos", 0)
else:
pos = self.pos
print args, kwargs
return self.type_map[type(args[pos])](*args, **kwargs)
except KeyError:
return self.default_function(*args, **kwargs)
except IndexError:
return self.default_function(*args, **kwargs)
def overload(self, *d_type):
def wrapper(f):
for dt in d_type:
self.type_map[dt] = f
return self
return wrapper
Cuando intento poner en práctica esta manera:
class MyClass(object):
def __init__(self):
self.some_instance_var = 1
@Overload
def print_first_item(self, x):
return x[0], self.some_instance_var
@print_first_item.overload(str)
def print_first_item(self, x):
return x.split()[0], self.some_instance_var
consigo una cuando lo ejecuto TypeError
:
>>> m = MyClass()
>>> m.print_first_item(1)
<__main__.Overload object at 0x2> (1,) {}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "overload.py", line 17, in __call__
return self.default_function(*args, **kwargs)
TypeError: print_first_item() takes exactly 2 arguments (1 given)
>>>
Mi pregunta es: ¿Cómo puedo acceder a la instancia de MyClass
(es decir, self
) desde dentro del método decorado?
¿Has mirado en la implementación de referencia en PEAK.Rules, o cualquiera de las docenas de otras implementaciones de referencia vinculados a la Pje PEP anteriores y publicaciones en la lista? Si intentas usar esto, en lugar de tratar de explorar Python, probablemente tenga más sentido usar su trabajo (que al menos algunas otras personas hayan usado y probado) que repetirlo. – abarnert
@abarnert: No estaba al tanto de esto. Gracias por el aviso. Habiendo dicho eso, realmente me pregunto por qué mi implementación no está funcionando como esperaba y cómo podría solucionarlo. Yo soy, como dices "explorando Python". –
Primero, ¿sabes de @ functools.wraps, etc.? Harán tu vida mucho más fácil, pero eso no te ayudará aquí. De todos modos, la primera parte del problema aquí es que su default_function está siendo reemplazada por una clase funcional que no es un método (Overload .__ call__ toma un self, pero esa es la instancia de Overload, no la MyClass). Pero obviamente no puedes simplemente hacer __call__ (self, realself, * args, ** kwargs) y esperar que eso funcione. No tengo tiempo para entrar en detalles esta noche; con suerte, alguien más puede ayudar antes de que regrese. – abarnert