我正在使用来自两个不同库的两个不同装饰器。比方说:@decorator1(param1, param2)
和@decorator2(param3, param4)
。我经常在许多功能中使用:
from moduleA import decorator1
from moduleB import decorator2
@decorator2(foo='param3', bar='param4')
@decorator1(name='param1', state='param2')
def myfunc(funcpar1, funcpar2):
...
因为它每次都会发生,所以我想创建一个自定义装饰器来处理它们。像这样的东西:
@mycustomdecorator(name='param1', state='param2',
foo='param3', bar='param4')
def myfunc(funcpar1, funcpar2):
...
我该如何实现?
我认为您不应该这样做——使用装饰器的原始名称可提供更好的可读性。
但是,如果你真的想,你可以这样做:
import functools
from moduleA import decorator1
from moduleB import decorator2
def my_decorator(foo, bar, name, state):
def inner(func):
@decorator2(foo=foo, bar=bar)
@decorator1(name=name, state=state)
@functools.wraps(func) # Not required, but generally considered good practice
def newfunc(*args, **kwargs)
return func(*args, **kwargs)
return newfunc
return inner
@my_decorator(foo='param3', bar='param4', name='param1', state='param2')
def myfunc(funcpar1, funcpar2):
...
虽然根据评论,这里有一个替代方法:
def my_decorator(foo, bar, name, state):
def inner(func):
# Please note that for the exact same result as in the other one,
# the order of decorators has to be reversed compared to normal decorating
newfunc = decorator1(name=name, state=state)(func)
newfunc = decorator2(foo=foo, bar=bar)(newfunc)
# Note that functools.wraps shouldn't be required anymore, as the other decorators should do that themselves
return newfunc
return inner
对某些人来说,这可能看起来更简单。但是,使用过 Python 的人习惯于使用 @ 应用装饰器——即使仅出于这个原因,我也更喜欢我的第一个选项。我知道第一次阅读这段代码并理解它的作用要花三倍的时间。
这真的很简单 - 只需编写一个返回另一个装饰器的装饰器,该装饰器将用其他两个装饰器装饰它的内部函数;)
为了养成良好的习惯,使用 functools.wraps 可能也是个好主意。它是标准库,对调试和交互式控制台使用有很大帮助:https://docs.python.org/3.7/library/functools.html
但总的来说,我认为多一行代码比单独使用装饰器更清晰。当您再过 3 个月阅读自己的代码时,您会感谢自己。