Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

255
Vistas
Agregue un decorador a una clase agregue un decorador a los métodos de la clase decorando la clase

Estoy tratando de crear un decorador que se pueda definir en la clase y decore todo lo definido en ella. Primero, déjame mostrarte la configuración que ya obtuve según otras respuestas de SO:

 import inspect # https://stackoverflow.com/a/18421294/577669 def log(func): def wrapped(*args, **kwargs): try: print("Entering: [%s]" % func) try: # https://stackoverflow.com/questions/19227724/check-if-a-function-uses-classmethod if inspect.ismethod(func) and func.__self__: # class method return func(*args[1:], **kwargs) if inspect.isdatadescriptor(func): return func.fget(args[0]) return func(*args, **kwargs) except Exception as e: print('Exception in %s : (%s) %s' % (func, e.__class__.__name__, e)) finally: print("Exiting: [%s]" % func) return wrapped class trace(object): def __call__(self, cls): # instance, owner): for name, m in inspect.getmembers(cls, lambda x: inspect.ismethod(x) or inspect.isfunction(x)): setattr(cls, name, log(m)) for name, m in inspect.getmembers(cls, lambda x: inspect.isdatadescriptor(x)): setattr(cls, name, property(log(m))) return cls @trace() class Test: def __init__(self, arg): self.arg = arg @staticmethod def static_method(arg): return f'static: {arg}' @classmethod def class_method(cls, arg): return f'class: {arg}' @property def myprop(self): return 'myprop' def normal(self, arg): return f'normal: {arg}' if __name__ == '__main__': test = Test(1) print(test.arg) print(test.static_method(2)) print(test.class_method(3)) print(test.myprop) print(test.normal(4))

Al eliminar el decorador @trace de la clase, este es el resultado:

 123 static class myprop normal

Al agregar el decorador @trace obtengo esto:

 Entering: [<function Test.__init__ at 0x00000170FA9ED558>] Exiting: [<function Test.__init__ at 0x00000170FA9ED558>] 1 Entering: [<function Test.static_method at 0x00000170FB308288>] Exception in <function Test.static_method at 0x00000170FB308288> : (TypeError) static_method() takes 1 positional argument but 2 were given Exiting: [<function Test.static_method at 0x00000170FB308288>] None Entering: [<bound method Test.class_method of <class '__main__.Test'>>] Exiting: [<bound method Test.class_method of <class '__main__.Test'>>] class: 3 Entering: [<property object at 0x00000170FB303E08>] Exiting: [<property object at 0x00000170FB303E08>] myprop Entering: [<function Test.normal at 0x00000170FB308438>] Exiting: [<function Test.normal at 0x00000170FB308438>] normal: 4

Conclusión de este ejemplo: los métodos init, normal, class y prop están todos correctamente instrumentados.

Sin embargo, el método estático no lo es.

Mis preguntas para este fragmento son:

  1. ¿Está bien verificar ciertos casos de uso como lo hice en el registro? ¿O hay un mejor camino?
  2. ¿Cómo ver si algo es un método estático para no poder pasar nada (porque ahora se pasa la instancia de prueba)?

¡Gracias!

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Mi solución final:

 import inspect from typing import Type from decorator import decorator @decorator def log(func, *args, **kwargs): try: print("Entering: [%s]" % func) return func(*args, **kwargs) finally: print("Exiting: [%s]" % func) def _apply_logger_to_class(cls): for attr in inspect.classify_class_attrs(cls): if attr.defining_class is not cls: continue if attr.kind == 'data': continue if isinstance(attr.object, (classmethod, staticmethod)): setattr(cls, attr.name, attr.object.__class__(log(attr.object.__func__))) elif isinstance(attr.object, property): setattr(cls, attr.name, property(log(attr.object.fget))) else: setattr(cls, attr.name, log(attr.object)) return cls def trace(func=None): if isinstance(func, type): return _apply_logger_to_class(func) # logger is the class return log(func) @trace def normal_function_call(arg): return f'normal_function_call: {arg}' @trace class Test: def __init__(self, arg): self.arg = arg print(f'{self.__class__.__name__}.__init__: {arg}') @staticmethod def static_method(arg): return f'Test.static: {1}' @classmethod def class_method(cls, arg): print(f'{cls.__name__}.class: {arg}') @property def myprop(self): print(f'{self.__class__.__name__}.myprop.getter') return 1 @myprop.setter def myprop(self, item): print(f'{self.__class__.__name__}.myprop.setter') @myprop.deleter def myprop(self): print(f'{self.__class__.__name__}.myprop.deleter') def normal(self, arg): print(f'{self.__class__.__name__}.normal: {arg}') @trace class TestDerived(Test): @staticmethod def static_method(arg): print(f'TestDerived.class: {arg}') if __name__ == '__main__': print(normal_function_call(0)) def do_test(test_class: Type[Test]): print('-'*20, test_class.__name__) test = test_class(1) test.static_method(2) test.__class__.static_method(2.5) test.class_method(3) test.__class__.class_method(3.5) test.myprop test.normal(4) assert inspect.getfullargspec(test.normal).args == ['self', 'arg'] assert inspect.getfullargspec(test.normal).kwonlyargs == [] do_test(Test) do_test(TestDerived)

Esto funciona según lo previsto para las clases derivadas, para todos los objetos que quiero, y conserva las firmas. (que @wraps no lo hace).

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda