一文学会Python装饰器

一些概念

函数是一等对象

拿其他函数作为参数或者返回值的函数叫作高阶函数

闭包和自由变量
在这里插入图片描述
整个空间叫闭包。
内部函数中访问的外部函数的局部变量叫作自由变量。

*args和**kwargs

@语法糖
在这里插入图片描述
在这里插入图片描述

装饰器的4种套路

在这里插入图片描述

否否

在这里插入图片描述

是否

在这里插入图片描述

以上两种只是在函数的定义时加了一些小动作。

否是

在这里插入图片描述

是是

在这里插入图片描述

真正的装饰器是inner_dec(f)
针对装饰器的配置函数写在它的外面。

针对被装饰函数的包装函数,加在inner_dec()的内层,是wrapper()

总结

三层def中,只有中间的装饰器函数是必须的,外层的是配置函数,内层的是包装函数。

实战

例子一

否否类型。

tasks = []


def task(f):
    global tasks
    tasks.append(f)
    setattr(f, "name", f.__name__)
    return f


@task
def play1():
    return "playing1..."


@task
def play2():
    return "playing2..."


def action():
    for task in tasks:
        print(task.__name__, ": ", task())


if __name__ == '__main__':
    action()

输出结果:

play1 :  playing1...
play2 :  playing2...

解读:
@task会在task1()和task2()定义时起作用,将他们添加到了tasks列表中。
在action()函数中会遍历tasks列表,将里面的task取出并调用。

例子二

是否类型。

tasks = []


def task(name=''):
    if callable(name):
        return task()(name)

    def _task(f):
        global tasks
        tasks.append(f)
        if name:
            setattr(f, 'name', name)
        else:
            setattr(f, "name", f.__name__)
        return f

    return _task


@task
def play1():
    return "playing1..."


@task("自定义2")
def play2():
    return "playing2..."


def action():
    for t in tasks:
        print(t.name, ": ", t())


if __name__ == '__main__':
    action()

这里可以学到在函数内部判断参数的类型。

例子三

from functools import partial


def complex_job(x, y, z):
    print(x, y, z)


def simplify(f, x, y):
    def dec(z):
        return f(x, y, z)

    return dec


simplified_job = simplify(complex_job, 1, 2)
simplified_job(3)

simplified_job2 = partial(complex_job, y=2, z=3)
simplified_job2(1)

这里是介绍一下functools库中的partial。

下面使用partial来写自己的my_wraps()

from functools import partial

tasks = []


def task(name=''):
    if callable(name):
        return task()(name)

    def _task(f):
        global tasks
        tasks.append(f)
        if name:
            setattr(f, 'name', name)
        else:
            setattr(f, "name", f.__name__)
        return f

    return _task


def count(f):
    counter = 0

    # 两个装饰器可以互相替代
    # @wraps(f)
    @my_wraps(f)
    def wrapper(*args, **kwargs):
        nonlocal counter
        counter += 1
        return f(*args, **kwargs) + ' ' + str(counter)

    # update_wrapper(wrapper, f)
    return wrapper


def update_wrapper(wrapper, f):
    setattr(wrapper, '__name__', f.__name__)
    setattr(wrapper, '__doc__', f.__doc__)
    return wrapper


def my_wraps(f):
    return partial(update_wrapper, f=f)


@task
@count
def play1():
    return "playing1..."


@task("自定义2")
@count
def play2():
    return "playing2..."


def action():
    for t in tasks:
        print(t.name, ": ", t())


if __name__ == '__main__':
    action()

参考资料

建议,直接看视频,比我讲得清楚 QAQ

https://www.bilibili.com/video/BV1Ra4y147oH
https://www.bilibili.com/video/BV1Wa4y1x7Kk

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wei *

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值