The World of TomasRan

简洁方便的Python装饰器

Python装饰器在实际的编码过程中使用非常广泛,它为Python中的函数编写提供了良好的扩展性,在拾获Python装饰器的相关概念、用法之前,我们先简单了解一下Python中函数的特性。

函数对象

在Python中一切即对象。

函数也不得不遵守Python界的自然法则。我们可以将函数作为参数进行传递。Python中,以自变量为参数的传递都是传递对象的引用。来看下面的例子:

Python装饰器

这是以函数为参数的一个很简单的例子,参数func是函数的引用,在调用的时候,我们将police作为参数传递进去,由此可见,函数的名称是一个指向函数对象的指针,这样,我们可以将不同的变量指向该函数对象并调用该函数。

thief竟然也成为了policeman!这样的替代在函数调用时依然是完全等价的。因此,我们可以将自己所喜欢的任意名称指向一个函数并能够获得它的所有特征。

装饰器

函数可作为参数进行传递是Python装饰器的基础。望文生义在文学艺术的鉴赏上并不是一个很好的习惯,但在计算机界,从字面上便能获取程序的一些设计信息和功能介绍却是每一段优秀代码的良好开端。就如计算机界的各种专业术语也是致力于秉承这优良品质。追求更加语义化。

这样,我们来分析一下装饰的含义,装饰就是给一个本来存在的东西进行一下外部的修饰,比如首饰,项链,各种化妆品等都是女孩用来锦上添花的装饰(当然也不排除雪中送炭)。Python中的装饰器也是起到了同样的效果:在函数的运行前后,动态扩展函数的功能。

看一看具体的适用方法:

1. 使用 “@” 语法糖来装饰函数:

为了提高程序代码的可读性,以及让装饰器具备自己的鲜明特征,Python中使用 “@” 语法糖来构建函数间的装饰关系。

Python装饰器

在Python的交互模式中,不论多行还是单行语句都会在输入结束之后立即运行。Python中的 “@” 语法糖实际上是执行了一个这样的过程:

police = person(police)

因为上例中我们定义的person函数并没有返回任何类型的对象,所以police被重新赋值之后是NoneType,这也是为什么再次调用police()会出错的原因。

那么该如何定义一个合格的装饰器函数呢?我们采用内嵌包装函数来实现。从上面的例子可以分析,我们需要person(police)执行结果返回一个函数,然后将police指向该函数。

Python装饰器

我们不难得到,之后调用的police函数实际上是指向了person中的decorate函数。

2. 装饰带参数的函数:

上面给出的例子中被装饰函数不带参数,然而在实际应用中,往往被装饰的函数是带有自己的参数的,带参数的函数如何被装饰呢?

Python装饰器

police('policewoman') 的调用和未装饰前的调用方式完全一样,我们只需要向person中的decorate函数的定义中也添加对应的参数就可以了(因为它实际上调用的就是person中的decorate函数)。

下面给出一个接受任意参数的装饰器例子(python中函数参数的几种形式在这里不做细究)。

Python装饰器

3. 装饰器带参数:

装饰器可以为装饰函数添加一些额外的功能,作为函数本身,装饰器本身有时也需要传递参数,请看下例:

Python装饰器

带有参数的装饰器,在定义完成后实际执行了这样一个过程:police = person('person')(police),即先返回了decorate函数,然后执行 decorate(police),将police重新指向返回的wrapper函数。

小结

对Python装饰器的应该算是有了一个全貌的把握,原理很简单,应用的时候需要特别注意高阶函数的返回值和参数设置。多留一点心,少制造一些bug。