我想列出所有用于功能的装饰器,就像这样工作
@a
@b(arg=1)
f():
pass
get_decorators(f) == ['a', 'b']
# or
get_decorators(f) == [a, b]
带一根胡萝卜,因为我们要在这个问题上掉进兔子洞……
如果装饰器很简单,这可能很简单:
def a(func):
try:
func.decorators.append('a')
except AttributeError:
func.decorators = ['a']
# decorator business
return func
def b(arg):
def _deco(func)
try:
func.decorators.append('b')
except AttributeError:
func.decorators = ['b']
# decorator business
return func
return _deco
@a
@b(arg=1)
def my_func():
pass
print(my_func.decorators) # Go full python and put attributes on your functions
但是当您将通用功能应用于多个功能时,您可以做什么?你重构当然要使用装饰器!所以,我可以介绍元装饰器。 (我还通过更改
b
返回包装纸来提高赌注)
def deco_tracker(decorator):
""" Meta-decorator for attaching decorator reference to decorated function
Applying this decorator to another decorator will result in the final decorated function
having an attribute called 'decorators' that stores references to it's decorators.
"""
def deco_wrapper(func):
returned_func = decorator(func) # Sometimes a wrapper is returned
try:
returned_func.decorators.append(decorator)
except AttributeError:
returned_func.decorators = [decorator]
return returned_func
return deco_wrapper
@deco_tracker
def a(func):
# decorator business
return func
def b(arg):
@deco_tracker
def _deco(func)
def wrapper(*args, **kwargs)
# decorator business
return func(*args, **kwargs)
return wrapper
return _deco
@a
@b(arg=1)
def my_func():
pass
print(my_func.decorators) # [<function b.<locals>._deco 0x19>, <function a at 0x7f>]
存储函数引用比存储名称的字符串表示更容易。它否定了解析包装器的复杂性。
元装饰器可以应用于第三方装饰器,只要它们不返回包装器即可。为此,您需要包装
deco_tracker
以生成 deco_wrapper_tracker
然后将正确的元装饰器变体应用于每个装饰器。对此的增强是检查 isinstance
的第一个传入参数 types.FunctionType
并从那里选择,但这假设采用 args 的装饰器从不采用函数,这是非常安全的选择,但并不理想。如果这得到足够的关注,我将生成示例代码。
类似这个问题,虽然历史比较久远,但是提供的方法是可用的: