Python:剥开“装饰器“的外衣

简介:装饰器本质是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下,在代码运行期间动态增加功能的方式,称之为 装饰器(Decorator),装饰器的返回值也是一个函数/类对象。

常见应用场景:
1、功能插入日志。
2、事务处理、增加缓存。
3、权限校验等。

案例:
1、基础入门装饰器案例
2、装饰器语法糖案例
3、被装饰函数多次装饰
4、被装饰函数含可变参数
5、带有参数的装饰器
6、类装饰器

入门案例:

# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发


def f():
    print("2022-05-27")


def dec(fun):
    def inner():
        print("处理函数f执行前的增加操作")
        fun()
        print("处理函数f执行后的增加操作")
    return inner


if __name__ == '__main__':
    # 处理函数f执行前的增加操作
    # 2022-05-27
    # 处理函数f执行后的增加操作
    f = dec(f)
    f()

起因:为扩展或者丰富f()函数的执行,例如在f()函数执行前后进行增加其他操作,那么可以通过装饰器解决这个问题。

本质:将f()这个函数放到其他函数中执行。

实现步骤:

1、新增的dec()的函数,形参fun,即def dec(fun):pass

def dec(fun):
    pass

2、dec中内部创建一个函数inner,这个函数内新增前置操作和后置操作,并且将dec的形参fun进行执行,并把inner返回。

def dec(fun):
    def inner():
        print("处理函数f执行前的增加操作")
        fun()
        print("处理函数f执行后的增加操作")
    return inner

3、调用说明:

if __name__ == '__main__':
    f = dec(f)
    f()

将原函数f()当成一个函数变量传给dec(fun)的形参fun,再用新增的f变量去接收这个返回值inner,再使用f()执行。这个过程中,原函数f被当成了变量传给了fun,并返回inner这个内部函数,即闭包。再次f()时,执行了inner(),即触发分别执行了前置操作、f()、后置操作三个操作。

原理:Python中函数也是对象,可以把一个函数当成变量传入函数中,也支持返回一个函数,形成闭包,调用返回的函数,则会触发执行内部的操作。从而实现了再不修改原函数的基础上,增加扩展了功能。

装饰器语法糖:上述写法既拗口,也泯灭人性,简便的写法如下。

# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发


def dec(fun):
    def inner():
        print("处理函数f执行前的增加操作")
        fun()
        print("处理函数f执行后的增加操作")

    return inner


@dec
def f():
    print("2022-05-27")


if __name__ == '__main__':
    # 处理函数f执行前的增加操作
    # 2022-05-27
    # 处理函数f执行后的增加操作
    f()

即:最终形成语法糖@dec def f(): … 的方式。

细节:此处的f()看起来像是执行f(),其实是执行的主函数为dec(fun)。原函数f()只是其中执行的一部分。把@dec放到f()函数的定义处,相当于执行了语句:f = dec(f)由于dec()是一个decorator,返回一个函数,所以,原来的f()函数仍然存在,只是现在同名的f变量指向了新的函数,于是调用f()将执行新函数,即在dec()函数中返回的inner()函数。

升级版装饰器1:被装饰函数多次装饰

离被装饰的函数最近的装饰器先装饰,然后外⾯的装饰器再进⾏装饰,由内到外的装饰过程。即:f穿上dec1的衣服,再带着这身衣服去穿dec2的衣服。

# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发


def dec1(fun):
    def inner():
        print("处理函数f执行前的增加操作:dec1")
        fun()
        print("处理函数f执行后的增加操作:dec1")

    return inner


def dec2(fun):
    def inner():
        print("处理函数f执行前的增加操作:dec2")
        fun()
        print("处理函数f执行后的增加操作:dec2")

    return inner


@dec2
@dec1
def f():
    print(f"2022-05-27")


if __name__ == '__main__':
    # 处理函数f执行前的增加操作:dec2
    # 处理函数f执行前的增加操作:dec1
    # 2022 - 05 - 27
    # 处理函数f执行后的增加操作:dec1
    # 处理函数f执行后的增加操作:dec2
    f()

升级版装饰器2:被装饰函数含可变参数

# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发


def dec(fun):
    def inner(*args, **kw):
        print("处理函数f执行前的增加操作")
        fun(*args, **kw)
        print("处理函数f执行后的增加操作")

    return inner


@dec
def f(*args, **kwargs):
    person_names = "-".join([i for i in args])
    print(f"你好!{person_names}{kwargs}。今天是2022-05-27")


if __name__ == '__main__':
    # 处理函数f执行前的增加操作
    # 你好!Tom - Lily。{'Jim': 'HK'}。今天是2022 - 05 - 27
    # 处理函数f执行后的增加操作
    
    # f("Tom", "Lily", Jim="HK")
    # f(*("Tom", "Lily"), **{'Jim': 'HK'})
    a = ("Tom", "Lily")
    b = {'Jim': 'HK'}
    f(*a, **b)

升级版装饰器3:带有参数的装饰器

使⽤装饰器装饰函数的时候可以传⼊指定参数;

语法格式: @装饰器外层函数名(参数,…)

使⽤带有参数的装饰器,其实是在装饰器外⾯⼜包裹了⼀个函数,使⽤该函数接收参数,返回是装饰器,因为@ 符号需要配合装饰器实例;使⽤装饰器只能接收⼀个参数,并且还是函数类型。

# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发


def dec1(flag):
    def mid(fun):
        def inner():
            if flag:
                # true 执行前置操作
                print("处理函数f执行前的增加操作")
                fun()
            else:
                # false 执行后置操作
                fun()
                print("处理函数f执行后的增加操作")

        return inner

    return mid


@dec1(3 > 2)
def f():
    print(f"2022-05-27")


if __name__ == '__main__':
    # 处理函数f执行前的增加操作
    # 2022 - 05 - 27
    f()

升级版装饰器4:类装饰器 - 装饰器还有⼀种特殊的⽤法就是类装饰器,就是通过定义⼀个类来装饰函数。

# -*- coding: utf-8 -*-
# time: 2022/5/27 0:19
# file: decorator.py
# 公众号: 玩转测试开发


class Decorator:
    def __init__(self, fun):
        self.fun = fun

    def __call__(self, *args, **kwargs):
        print("类装饰器:执行f函数的前置操作")
        self.fun()
        print("类装饰器:执行f函数的后置操作")


@Decorator
def f():
    print(f"2022-05-27")


if __name__ == '__main__':
    # 类装饰器:执行f函数的前置操作
    # 2022-05-27
    # 类装饰器:执行f函数的后置操作
    f()

微信公众号:玩转测试开发
欢迎关注,共同进步,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值