Python dynamically add decorator to class' methods by decorating class

后端 未结 2 1259
谎友^
谎友^ 2020-12-13 22:11

say I have a class:

class x:

    def first_x_method(self):
        print \'doing first_x_method stuff...\'

    def second_x_method(self):
        print \'d         


        
相关标签:
2条回答
  • 2020-12-13 22:54

    Here's a version of the trace decorator implemented as a class which allows for the other use case asked for: passing in the function to decorate all member functions of the decorated class with.

    import inspect
    
    
    def log(func):
        def wrapped(*args, **kwargs):
            try:
                print "Entering: [%s] with parameters %s" % (func.__name__, args)
                try:
                    return func(*args, **kwargs)
                except Exception, e:
                    print 'Exception in %s : %s' % (func.__name__, e)
            finally:
                print "Exiting: [%s]" % func.__name__
        return wrapped
    
    
    class trace(object):
    
        def __init__(self, f):
            self.f = f
    
        def __call__(self, cls):
            for name, m in inspect.getmembers(cls, inspect.ismethod):
                setattr(cls, name, self.f(m))
            return cls
    
    
    @trace(log)
    class X(object):
    
        def first_x_method(self):
            print 'doing first_x_method stuff...'
    
        def second_x_method(self):
            print 'doing second_x_method stuff...'
    
    x = X()
    x.first_x_method()
    x.second_x_method()
    
    0 讨论(0)
  • 2020-12-13 22:55

    Unless there is a definite reason to use a class as a decorator, I think it is usually easier to use functions to define decorators.

    Here is one way to create a class decorator trace, which decorates all methods of a class with the log decorator:

    import inspect
    
    
    def log(func):
        def wrapped(*args, **kwargs):
            try:
                print("Entering: [%s] with parameters %s" % (func.__name__, args))
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print('Exception in %s : %s' % (func.__name__, e))
            finally:
                print("Exiting: [%s]" % func.__name__)
        return wrapped
    
    
    def trace(cls):
        # https://stackoverflow.com/a/17019983/190597 (jamylak)
        for name, m in inspect.getmembers(cls, lambda x: inspect.isfunction(x) or inspect.ismethod(x)):
            setattr(cls, name, log(m))
    
        return cls
    
    
    @trace
    class X(object):
        def first_x_method(self):
            print('doing first_x_method stuff...')
    
        def second_x_method(self):
            print('doing second_x_method stuff...')
    
    
    x = X()
    x.first_x_method()
    x.second_x_method()
    

    yields:

    Entering: [first_x_method] with parameters (<__main__.X object at 0x7f19e6ae2e80>,)
    doing first_x_method stuff...
    Exiting: [first_x_method]
    Entering: [second_x_method] with parameters (<__main__.X object at 0x7f19e6ae2e80>,)
    doing second_x_method stuff...
    Exiting: [second_x_method]
    
    0 讨论(0)
提交回复
热议问题