Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

256
Views
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 answers
Answer question

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!