Home > Back-end >  The elegant way to mark a set of member functions
The elegant way to mark a set of member functions

Time:09-29

I want to write a class Tool whose some member functions will be processed by another class, so I want to mark them explicitly and elegantly. For example,

class Tool:
    def __init__(self):
        self._marked = []

    @mark # how to add func1 to self._marked?
    def func1():
        """I will be processed"""
    
    def func2():
        """I will not be processed"""

    def marked_funcs():
        """return all marked functions"""
        return self._marked

However, the function decorator mark cannot access self, so I cannot add the decorated functions to self._marked. How can I do this, or is there any other elegant way to achieve this requirement?

CodePudding user response:

I think this is close to what you want to achieve.

  • I find it difficult to design a decorator to edit the class object (self._marked in the original code). So I create a "global" storage for the marked functions (_marked).
  • When invoking the mark decorator, this function is added to the _marked set.
  • I define the marked_funcs as a class method. This is because what the decorator receive is Tool.func1, not the method of the instance.
  • As a result, _marked_funcs returns its member functions that are marked.
_marked = set()

def mark(func):
    _marked.add(func)
    return func

def is_marked(func):
    return callable(func) and (func in _marked)
  
# test
@mark
def one():
    return 1
is_marked(one)
# True
class Tool:
    @mark # how to add func1 to self._marked?
    def func1():
        """I will be processed"""
    
    def func2():
        """I will not be processed"""

    @classmethod
    def marked_funcs(cls):
        """return all marked functions"""
        out = []
        for name in dir(cls):
            obj = getattr(cls, name)
            if is_marked(obj):
                out.append(obj)
        return out

t = Tool()
t.marked_funcs()
# [<function __main__.Tool.func1()>]

Tool.marked_funcs()
# [<function __main__.Tool.func1()>]

CodePudding user response:

I have a simple idea and it works. There is no need to use a list to store marked functions. I can add new property to the functions that I need to mark, and when necessary, I search for functions which has this property through traversal. For example:

def register(func):
    func.x = 1
    return func


class A:
    @register
    def hello1(self, a, b, c):
        print(f"a={a}, b={b}, c={c}")

    @register
    def hello2(self, a, b, c):
        print(f"a={a}, b={b}, c={c}")

    def registered_functions(self):
        res = []
        for func_name in dir(self):
            func = getattr(self, func_name)
            if hasattr(func, 'x'):
                res.append(func)
        return res


if __name__ == '__main__':
    a = A()
    print(a.registered_functions())
    # [<bound method A.hello1 of <__main__.A object at 0x7f7bd815aca0>>, <bound method A.hello2 of <__main__.A object at 0x7f7bd815aca0>>]
  • Related