La creación de un decorador dentro de la clase como método da error consigo mismo

Estoy tratando de crear un decorador dentro de la clase y necesito acceder a mí mismo dentro del decorador.

este es mi codigo

import functools
class Rtest(object):

    def __init__(self, *args, **kwargs):
        self.key1 = "foo"
        self.value1 = "bar"


    def continue_exception(self, func, **kwargs):
            @functools.wraps(func)
            def inner_function(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    import traceback
                    print(f"Error with {kwargs.get('key')} :  {kwargs.get('value')}")
                    print(f"Exception {traceback.format_exc()}")
                    return
            return inner_function

    def add1(self, n1, n2):
        return n1 + n2

    @continue_exception(key=self.key1, value=self.value1)
    def add2(self, n1, n2):
        return n1 + n2


obj = Rtest()

print(obj.add1(4,5))

print(obj.add2("fdfd", 6))

me sale este error

@continue_exception(key="foo", value="bar")

TypeError: continue_exception() faltan 2 argumentos posicionales requeridos: 'self' y 'func'

Answer

Su programa tiene los siguientes problemas:

  1. Hay un problema con la definición de su función de decorador. Cuando se usa en @continue_exception(key="foo", value="bar"), no hay ningún funcparámetro, solo recibirá los parámetros posicionales que le pases. Porque en este momento se ejecuta primero y luego se realiza la función de decoración.

  2. continue_exceptiones un método de instancia, no puede usarlo como decorador a menos que pueda pasarle un objeto. Entonces puede convertirlo en un método estático, sí, puede, porque selfno se usa dentro de la función.

El siguiente código soluciona el problema anterior y se ejecuta correctamente.

import functools
class Rtest(object):

    def __init__(self, *args, **kwargs):
        self.key1 = "foo"
        self.value1 = "bar"


    @staticmethod
    def continue_exception(**kwargs):
        def wrapper(func):
            @functools.wraps(func)
            def inner_function(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    import traceback
                    print(f"Error with {kwargs.get('key')} :  {kwargs.get('value')}")
                    print(f"Exception {traceback.format_exc()}")
                    return
            return inner_function
        return wrapper

    def add1(self, n1, n2):
        return n1 + n2

    @continue_exception(key="foo", value="bar")
    def add2(self, n1, n2):
        return n1 + n2


obj = Rtest()

print(obj.add1(4,5))

print(obj.add2("fdfd", 6))

Producción:

9
Error with None :  None
Exception Traceback (most recent call last):
  File "/home/wujun/Projects/code_test/test.py", line 15, in inner_function
    return func(*args, **kwargs)
  File "/home/wujun/Projects/code_test/test.py", line 29, in add2
    return n1 + n2
TypeError: can only concatenate str (not "int") to str

None

Si desea obtener los valores de key1y value1en tiempo real, puede realizar las siguientes modificaciones.

import functools
class Rtest(object):

    def __init__(self, *args, **kwargs):
        self.key1 = "foo"
        self.value1 = "bar"


    @staticmethod
    def continue_exception(func):
        @functools.wraps(func)
        def inner_function(*args, **kwargs):
            self, *_ = args
            try:
                return func(*args, **kwargs)
            except Exception as e:
                import traceback
                print(f"Error with {self.key1} :  {self.value1}")
                print(f"Exception {traceback.format_exc()}")
                return
        return inner_function

    def add1(self, n1, n2):
        return n1 + n2

    @continue_exception
    def add2(self, n1, n2):
        return n1 + n2


obj = Rtest()

print(obj.add1(4,5))

print(obj.add2("fdfd", 6))