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 isTool.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>>]