因为堆叠装饰器虽然说不是不行,但是随着项目越来越大,装饰器越堆越多,我们希望将一些关联性强的装饰器合并在一起,而不是像下面的代码一样,搞得像叠罗汉一样
# 公司业务代码其中一个接口 【flask-restplus】
class Goods(Resource)
@staticmethod
@document.request_goods_payload
@document.response_goods_id_success
@document.response_goods_time_format_error
@document.response_goods_name_format_error
@document.response_goods_weight_format_error
@document.response_goods_volume_format_error
@document.response_goods_expect_price_format_error
@document.response_goods_description_format_error
@document.response_goods_same_address_error
@document.response_goods_require_vehicle_error
@document.response_add_goods_duplicate
@document.response_unauth_restriction
@document.response_auth_restriction
@catch_exception_log()
@filters.Goods.return_goods_id(goods_id=int, is_dispatch=int, is_prepaid=int)
@dispatchs.Goods.start(goods_id=int, is_dispatch=int, is_prepaid=int)
@operations.Goods.add_goods(user_id=int, payload=dict, app_version=str)
@config_operation.ConfigOperation.get_feed_config(user_id=int, payload=dict, app_version=str)
@operations.Goods.check_duplicate_goods(user_id=int, payload=dict, app_version=str)
@operations.Goods.check_add_goods_restriction(user_id=int, payload=dict, app_version=str)
@verifies.Goods.check_goods_payload_fields(user_id=int, app_version=str, payload=dict, code=str, channel=str)
@verifies.Token.token(token=str, app_version=str, payload=dict, code=str, channel=str)
def post():
""" 预约回头车【需登录】 """
pass
import functools
def deco1(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("deco1")
return func(*args, **kwargs)
return wrapper
def deco2(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("deco2")
return func(*args, **kwargs)
return wrapper
# 方法一:通过参数的里的元组(包含很多个装饰器)
def composed(*decs, is_reversed=False):
def deco(f):
if is_reversed:
for dec in reversed(decs):
f = dec(f)
else:
for dec in decs:
f = dec(f)
return f
return deco
# 方法二:用指定的多个装饰器将调用链写好先,缺点是每次要加多一个装饰器调用,需要改源代码
def mutiple_deco(func):
return deco2(deco1(func))
# 方法三:先通过函数调用获得一个装饰器函数先,然后再装饰目标函数
def generate_deco(f, g):
return lambda x: f(g(x))
# 原来的装饰器装饰方式
@deco2
@deco1
def add(a: int, b: int) -> int:
return a + b
@composed(deco1, deco2, is_reversed=False)
def add_method1(a: int, b: int) -> int:
return a + b
@mutiple_deco
def add_method2(a: int, b: int) -> int:
return a + b
combined_deco = generate_deco(deco2, deco1)
@combined_deco
def add_method3(a: int, b: int) -> int:
return a + b
if __name__ == "__main__":
r = add(10, 1)
print("结果是:", r)
r = add_method1(10, 2)
print("结果是:", r)
r = add_method2(10, 3)
print("结果是:", r)
r = add_method3(10, 4)
print("结果是:", r)
# 【flask-restplus】
class ApiClass(Resource)
@staticmethod
@multi_deco(DOC1, DOC2...)
@multi_deco(FILTER1, FILTER2...)
@multi_deco(DISPATCH1, DISPATCH2...)
@multi_deco(OPERATION1, OPERATION2...)
@multi_deco(VERIFY1, VERIFY2...)
def post():
""" 接口文档 """
pass
装饰器合并是一个很好玩的东西,可以将以往无限堆装饰器的方式做的更优雅,一个装饰器调用将相关功能的装饰器放在一起,就很舒服,很爽,天天写代码,也得考虑下优化的方法。