Python 函数装饰器

137 阅读2分钟

函数装饰器用于在代码中标记函数,以某种方式增强函数的行为。装饰器是可以调用的函数对象,其参数是另外一个函数。装饰器在被调用的过程中可以增强参数代表的函数,也可以直接返回并做一些额外的注册类的工作。

基本格式

  1. 定义一个装饰器函数,对传入的函数进行包装,例如本例中定义一个替换的函数replace_func,在函数中可以做一些额外的处理,比如增强函数的功能或者附件功能或者注册到某个消息、或功能中心。
  2. 定义在实际调用的地方定义原本函数的功能,并在前面采用@+装饰器函数的方式@decorate用来标记。 这样在调用target函数的时候,实际执行的就是replace_func函数。
#装饰器函数
def decorate(func):
    def replace_func():
        # 对传入的函数进行处理,增强原来函数的一些功能,或者注册功能
        print("replace_func running --> target " + str(func))

    return replace_func


@decorate
def target():
    print("test_decorate running")


if __name__ == "__main__":
    print("running main --> target:" + str(target))
    target()

执行的结果:

running main --> target:<function decorate.<locals>.replace_func at 0x0000027501A613A0>
replace_func running --> target <function target at 0x0000027501A61700>

从执行的结果上看,主函数打印的target函数实际就是replace_func函数,而在replace_func函数中打印的传入参数就是带装饰器描述符的target函数。

实际上面的功能就是将target函数传入一个函数(装饰器函数),装饰器函数对target函数进行了一些的处理的结果,类似target = decorate(target)的形式,这种实现的方法实际上就是简化了写法而已。

def decorate(func):
    def replace_func():
        # do some things
        print("replace_func running --> target " + str(func))

    return replace_func


# @decorate
def target():
    print("test_decorate running")


if __name__ == "__main__":
    target = decorate(target)
    print("running main --> target:" + str(target))
    target()

执行结果:

running main --> target:<function decorate.<locals>.replace_func at 0x00000297481D13A0>
replace_func running --> target <function target at 0x00000297481D1700>

从上面的执行结果来看,结果是完全相同的,二者的实现的等效的。

应用场景:集中注册

在购物管理的网站上经常会出现类似的应用场景:促销购物中经常会出现很多打折的情况,比如plus会员、购物满足多少额度、商品的类型组合情况的打折等等,在计算打折的时候我们可以使用函数装饰器进行当前商品可以享受的打折力度。

promos = []

#注册函数的目的,没有做任何附加的处理
def promotion(promo_func):
    promos.append(promo_func)
    return promo_func


@promotion
def promo_plus(shopping_cart, discount):
    # do somethings
    return discount


@promotion
def promo_combo(shopping_cart, discount):
    # do somethings
    return discount


@promotion
def promo_type(shopping_cart, discount):
    # do somethings
    return discount


def get_discount():
    shopping_cart = []
    discount = 1
    for promo in promos:
        discount = promo(shopping_cart, discount)