python装饰器简单理解

装饰器

理解前提:

1. 函数可以作为参数进行传递

2. 函数可以直接被返回

3. 函数可以被赋值给变量

4. 函数内可以再次定义函数

初步认识

为了方便理解,先从举例开始,首先定义了一个函数:


函数功能:输出一个字符串。然而,老大提出需求,在不改变原函数的功能(代码)前提下对输出的字符串进行标签处理,这里有一个最直观的方案是:


定义函数decorator,接收一个函数作为参数;定义内部函数wrapper,引用外部函数的参数并执行,然后对结果进行加工,最后decorator函数将内部函数返回

调用decorator函数,传入需要处理的hello_world函数,将返回值赋值给变量after,然后执行after(),得到最终结果,完成需求

这里讲文章开始提到的几点前提全部涉及到了,所以比较关键的点是必须理解前提中说到的几点

这里需要提一点,看下图:


这里打印的函数名既不是after,也不是hello,而是wrapper。至于为什么会这样?如何解决?后文给出方案

上面我们整理下是如何处理的,完整代码:


从代码可以看出,decorator函数『装饰』了函数hello_world,所以用python专业术语来说,decorator函数就是一个装饰器,装饰器decorator装饰了hello_world函数后,返回给一个变量(本质上是一个函数)

上面的代码,用python化的写法是:


@是python提供的语法糖,非常便捷好用

初步总结就是:可以动态修改函数(或类)功能的函数就是装饰器

使用形式

经过上面一个简单例子,可以了解到,装饰器的使用形式是:


等同于:


一个函数,可以被多个装饰器进行装饰:


等同于:


函数(或类)都会有参数,装饰器本质也是函数(或类),如:


等同于:


对带参函数进行装饰

使用上面的例子,如下:


可以看到,hello_world传入的参数coco产生了作用

从上面的例子可以简单总结:装饰器内部函数作为参数接收方,将参数传递给外部函数参数func,也就是说,内部函数的参数需要和被装饰的函数参数对应!至于为什么使用*args,**kwargs,请自行了解

带参数的装饰器

这里有一个新需求,需要更换添加的标签,应该如何处理?直接修改装饰器的内部的代码显然不合理,但是不改代码好像不太好实现,这里需要对装饰器代码重构一下,如下:


在原decorator函数的外层,添加了一个带参的方法,改方法返回了decorator函数,并修改了装饰函数

简单理解就是:在装饰器外层添加一层包装,根据不同的参数返回不同的装饰器

基于类的装饰器

上面说的都是基于函数的装饰器,其实类也可以做装饰器,请看:


类中有两个关键方法:

__init__:接收函数作为初始化参数

__call__:接收被装饰函数的参数

类装饰器带参数:


和上面对比发现:如果类装饰器有参数,则__call__方法接收被装饰函数

装饰器的副作用

上面提到过,被装饰的函数,它的函数名已经不是原来的名称。

第一个例子提到:

hello_world被装饰之后,打印了函数名,名称变成了wrapper。

为了消除副作用,Python有一个自带的functools模块中,提供了名为wraps的装饰器:


上例可以看出,hello_world还是原来的名称

小结

装饰器就是将函数作为参数并且返回函数的高阶函数

装饰器可以动态的扩展函数功能,所以在代码的延展性方面装饰器使用比较广泛

装饰器其实就是闭包的一种应用(闭包:内部函数引用了外部函数的相关参数和自由变量,该返回的内部函数就是闭包)


你可能感兴趣的:(python装饰器简单理解)