Я пишу декоратор функции, который применяет преобразование к первому аргументу функции. Он отлично работает, если я украшаю свои функции только один раз, но если я украшаю их дважды, я получаю сообщение об ошибке. Ниже приведен код, демонстрирующий проблему, это упрощенная версия кода, над которым я работаю.Я исключил код, который выполняет преобразование, чтобы не отвлекать от проблемы
from inspect import getargspec
from functools import wraps
def dec(id):
def _dec(fn):
@wraps(fn)
def __dec(*args, **kwargs):
if len(args):
return fn(args[0], *args[1:], **kwargs)
else:
first_arg = getargspec(fn).args[0]
new_kwargs = kwargs.copy()
del new_kwargs[first_arg]
return fn(kwargs[first_arg], **new_kwargs)
return __dec
return _dec
@dec(1)
def functionWithOneDecorator(a, b, c):
print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)
@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)
functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)
functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)
Когда я запускаю приведенный выше код, я получаю следующий результат:
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithOneDecorator(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
functionWithTwoDecorators(a = 1, b = 2, c = 3)
IndexError: list index out of range
Это потому, что, когда второй декоратор проверяет функцию, которую он украшает, чтобы найти имена аргументов и не удается, потому что он украшает декоратор и принимает только * args и ** kwargs.
Я могу придумать способы решения проблемы, которые сработали бы в приведенном выше коде, но все равно сломались бы, если бы функция была оформлена моим декоратором, а другая - сторонним. Есть ли общий способ исправить это? или есть лучший способ достичь того же результата?
Обновление: Спасибо @Hernan за указание на модуль декоратора . Это точно решает эту проблему. Теперь мой код выглядит так:
from decorator import decorator
def dec(id):
@decorator
def _dec(fn, *args, **kwargs):
return fn(args[0], *args[1:], **kwargs)
return _dec
@dec(1)
def functionWithOneDecorator(a, b, c):
print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c)
@dec(1)
@dec(2)
def functionWithTwoDecorators(a, b, c):
print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c)
functionWithOneDecorator(1, 2, 3)
functionWithOneDecorator(1, b=2, c=3)
functionWithOneDecorator(a=1, b=2, c=3)
functionWithOneDecorator(c=3, b=2, a=1)
functionWithTwoDecorators(1, 2, 3)
functionWithTwoDecorators(1, b=2, c=3)
functionWithTwoDecorators(a=1, b=2, c=3)
functionWithTwoDecorators(c=3, b=2, a=1)
Намного чище, и он работает!