Python 装饰器

装饰器


在加强原函数的功能的同时,不修改原函数的定义,这种在代码运行期间动态增长功能的方式,就称为装饰器(Decorator)。装饰器,本质是一个返回函数的高阶函数。在了解装饰器以前,也简单介绍下返回函数的相关内容。python

返回函数


以前,咱们讲太高阶函数,map()filter() 函数等高阶函数,可以接受函数做为参数,而函数一样也能够做为结果值返回。微信

先定义一个简单的函数:闭包

>>> def func():    
...     print("return function")

上述代码只是普通的一个函数。如果,不须要当即输出,能够返回函数,而不是直接输出:app

>>> def return_func():
...     def func():
...         print("return function")
...     return func

当调用 return_func() 时,返回的不是输出结果,而是函数:函数

>>> f = return_func() 
>>> f
<function return_func.<locals>.func at 0x000002C03AF091E0>

当调用 f 时,才输出内容:日志

>>> f()
return function

这是返回函数的简单应用。code

闭包


闭包,是指在一个函数内部定义了另外一个函数,而内部函数引用了外部函数的参数和局部变量,当返回内部函数时,相关参数和变量存储在返回的函数中。orm

下面代码实现一个闭包的操做:get

>>> def lazy_sum(*args):
...     def sum():
...         num = 0 
...         for x in args:
...             num += x 
...         return num
...     return sum
...

这个例子中,内部函数调用了外部函数的参数 args,当调用 lazy_sum 时,返回的函数存储着相关参数和变量。只有当再次调用返回函数,才会得出运算结果。io

>>> f = lazy_sum(1,2,3,4,5)
>>> f
<function lazy_sum.<locals>.sum at 0x000002C03AF31488>
>>> f()
15

这里须要注意,每次调用外部函数,返回的函数都是新的函数,即便传入的参数都相同:

>>> f1 = lazy_sum(1,2,3,4,5) 
>>> f2 = lazy_sum(1,2,3,4,5) 
>>> f1 is f2
False
>>> f1 == f2 
False

该例子中,f1()f2() 的结果互不影响。

还有个须要注意的地方,返回函数不是马上执行,而是调用了 f() 才执行。尝试用另一个例子说明这种状况,示例以下:

>>> def count():
...     lst = []
...     for i in range(1, 4):
...         def func():
...             return i * i
...         lst.append(func)
...     return func
...
>>> f1, f2, f3 = count()

在这个例子中,每次循环,都建立一个新的函数,将建立的 3 个函数返回。

这里的结果,可能会猜想调用 f1(), f2(), f3() 结果分别是 1, 4, 9,但实际结果却都是 9

>>> f1()
9
>>> f2()
9
>>> f3()
9

这里是由于返回的函数引用了变量 i,可是没有马上执行。等 3 个函数都返回时,引用的变量 i 的值已经所有变成了 3,因此最终结果是 9

因此,返回闭包时,返回函数不要引用循环变量,或者后续会发生变化的值。

装饰器


前面已经说明,装饰器,本质上是一个返回函数的高阶函数。尝试用例子说明,

>>> def log(func):                      
...     def warpper(*args, **kw):       
...         print('call {}():'.format(func.__name__)
...         return func(*args, **kw)
...     return wrapper

上面的 log 是一个装饰器,接受函数做为参数,返回函数。借助 Python 的 @ 语法,把装饰器置于函数的定义处:

@log
def func():
    print("function name")

调用 func() 函数,会运行 func() 自己函数,还会在运行 func() 前,打印一行日志:

>>> func()
call func():
function name

在这里,将 @log 放到 func() 函数的定义处,至关于下列语句:

func = log(func)

因为 log() 是装饰器,返回一个函数。可是,原来的 func() 还存在,只是如今同名的 func() 指向了新的函数,因此调用的 func() 时,执行的将是 wrapper() 函数。在 wrapper() 函数内,首先先打印日志,而后再调用原始函数。

这些就是装饰器的一些内容,至于更深刻的部分,后续会继续更新介绍。


以上就是本篇的主要内容

题外话: 近期网上散布不少的谣言,致使不少人没法正确识别真假。下面的连接,是腾讯新闻的一个平台【较真】,实时给你们辟谣以及科普,能够帮助你们分清真相。尽可能作到不传谣不信谣。

https://vp.fact.qq.com/home

欢迎关注微信公众号《书所集录》
相关文章
相关标签/搜索