Python-一些关于装饰器的点

本质:函数闭包的语法糖

通过主功能+辅助功能,通调用主要函数实现主要功能和辅助功能

一、闭包

1. 本质上是一个函数

2. 传入参数和返回值都是函数

3. 闭包函数的返回函数是对传入函数增强后的结果(在不侵入代码的情况下对函数进行增强)

个人理解:函数里套函数,返回的函数会赋值给一个变量,这个变量可以在后面被继续执行调用。

案例:

外部函数nth_power返回的是内部函数exponent_of的引用 

对比 :

优点:

1. 在每次调用函数时,都可以少输入一个参数,更简洁
2. 函数开头需要做一些额外工作,当需要多次调用该函数时,如果将那些额外工作的代码放在外部函数,就可以减少多次调用导致的不必要开销,提高程序的运行效率。

二、语法糖

没有增加新功能,只是一种方便的写法

三、装饰器

第一次调用被装饰函数时进行增强,只增加一次

@+闭包函数名字

装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景.

1. 默认参数

Python当中支持任意参数,它写成*args, **kw。表示的含义是接受任何形式的参数

**kwargs 会把多传入的参数以 dict 形式存放(关键字参数)

例如:我们定义一个函数(运行无结果,需要调用)

def exp(a, b, c='3', d='f'): 

#默认参数即在函数定义阶段,就已经为形参赋值,目的是简化调用,你只需要把必须的参数传进去。
但是在需要的时候,又可以传入额外的参数来覆盖默认参数值。
   
    print(a, b, c, d)

我们可以这样调用:

args = [1, 3]
dt = {'c': 4, 'd': 5}

exp(*args, **dt)

形参可直接传入数据(a、b),默认参数用字典dict传入覆盖,形式为字典

注意我们传入list和dict的时候前面加上了*和**,它表示将list和dict当中的所有值展开。如果不加的话,list和dict会被当成是整体传入。

如果不想覆盖默认参数

def func(a,b,c='3',d='f'):
    print(a,b,c,d)

args = [1, 0]
func(*args, ) # 输出1,0,3,f

以上函数等价于

def func(a,b,c,d): # 都是形参,故调用时传入为list格式
    print(a,b,c,d)

args = [1, 0, 3, 2]
func(*args)  # 分隔开,若不添加*则报错,看做整体传入

所以如果一个函数写成这样,它表示可以接受任何形式的参数。

2. 装饰器本质

如果我们把函数A和这个函数A的所有参数全部传入另外一个函数B,以后要实现功能时,只需要调用这个函数B,就可以实现功能,这就相当于代理。

装饰器的本质其实就是这样一个agent函数,但是如果使用的时候需要手动传入会非常麻烦,使用起来不太方便。所以Python当中提供了特定的库,我们可以让装饰器以注解的方式使用,大大简化操作:

from functools import wraps

def wrapexp(func):
    def wrapper(*args, **kwargs):
        print('this is a wrapper')
        func(*args, **kwargs)
    return wrapper


@wrapexp
def exp(a, b, c='3', d='f'):
    print(a, b, c, d)


args = [1, 3]
dt = {'c': 4, 'd': 5}

exp(*args, **dt)

在这个例子当中,我们定义了一个wrapexp的装饰器。我们在其中的wrapper方法当中实现了装饰器的逻辑,wrapexp当中传入的参数func是一个函数,wrapper当中的参数则是func的参数。所以我们在wrapper当中调用func(*args, **kw),就是调用打上了这个注解的函数本身。比如在这个例子当中,我们没有做任何事情,只是在原样调用之前多输出了一行’this is a wrapper',表示我们的装饰器调用成功了。

参考文献:

Python 函数装饰器 | 菜鸟教程 (runoob.com)

一文搞定Python装饰器,看完面试不再慌 - 知乎 (zhihu.com)

总结

1. 什么是装饰器

装饰器本质上是一个 Python 函数或类,它可以让其他函数或类在不需要做任何代码修改的前提下增加额外功能,装饰器的返回值也是一个函数/类对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

2. 使用场景

  • 缓存
  • 权限校验(如django中的@login_required和@permission_required装饰器)
  • 性能测试(比如统计一段程序的运行时间)
  • 插入日志

3. 用处

在不修改函数内部代码的前提下,为它包装一些额外的功能。

猜你喜欢

转载自blog.csdn.net/Kiraxqc/article/details/126094532