Writing a class decorator that applies a decorator to all methods

后端 未结 3 1742
情歌与酒
情歌与酒 2020-12-13 16:26

I\'m trying to write a class decorator that applies a decorator to all the class\' methods:

import inspect


def decorate_func(func):
    def wrapper(*args,          


        
相关标签:
3条回答
  • 2020-12-13 16:47

    (Too long for a comment)

    I took the liberty of adding the ability to specify which methods should get decorated to your solution:

    def class_decorator(*method_names):
    
        def wrapper(cls):
    
            for name, meth in inspect.getmembers(cls):
                if name in method_names or len(method_names) == 0:
                    if inspect.ismethod(meth):
                        if inspect.isclass(meth.im_self):
                            # meth is a classmethod
                            setattr(cls, name, VerifyTokenMethod(meth))
                        else:
                            # meth is a regular method
                            setattr(cls, name, VerifyTokenMethod(meth))
                    elif inspect.isfunction(meth):
                        # meth is a staticmethod
                        setattr(cls, name, VerifyTokenMethod(meth))
    
            return cls
    
        return wrapper
    

    Usage:

    @class_decorator('some_method')
    class Foo(object):
    
        def some_method(self):
            print 'I am decorated'
    
        def another_method(self):
            print 'I am NOT decorated'
    
    0 讨论(0)
  • 2020-12-13 16:55

    inspect.isclass(meth.im_self) should tell you whether meth is a class method:

    def decorate_class(cls):
        for name, meth in inspect.getmembers(cls, inspect.ismethod):
            if inspect.isclass(meth.im_self):
              print '%s is a class method' % name
              # TODO
            ...
        return cls
    
    0 讨论(0)
  • 2020-12-13 17:07

    The above answers do not apply directly to python3. Based on the other great answers I have been able to come up with the following solution:

    import inspect
    import types
    import networkx as nx
    
    
    def override_methods(cls):
        for name, meth in inspect.getmembers(cls):
            if name in cls.methods_to_override:
                setattr(cls, name, cls.DecorateMethod(meth))
        return cls
    
    
    @override_methods
    class DiGraph(nx.DiGraph):
    
        methods_to_override = ("add_node", "remove_edge", "add_edge")
    
        class DecorateMethod:
    
            def __init__(self, func):
                self.func = func
    
            def __get__(self, obj, cls=None):
                def wrapper(*args, **kwargs):
                    ret = self.func(obj, *args, **kwargs)
                    obj._dirty = True  # This is the attribute I want to update
                    return ret
                return wrapper
    
        def __init__(self):
            super().__init__()
            self._dirty = True
    

    Now anytime a method in the tuple methods_to_override is called, the dirty flag is set. Of course, anything else can be put there too. It is not necessary to include the DecorateMethod class in the class whose methods need to be overriden. However, as DecorateMehod uses specific attributes to the class, I prefer to make a class attribute.

    0 讨论(0)
提交回复
热议问题