装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。在程序开发中经常使用到的功能,合理使用装饰器,能让我们的程序如虎添翼。

1 装饰器初识

装饰器本质: 就是一个 python 函数,他可以让其他函数在不需要做任何代码变动的前提下,增加额外的功能,装饰器的返回值也是一个函数对象。

装饰器的应用场景:比如插入日志,性能测试,事务处理,缓存等等场景。

import time


def timmer(f):
    def inner():
        start_time = time.time()
        f()
        end_time = time.time()
        print('此函数的执行时间为{}'.format(end_time - start_time))

    return inner


def func1():
    print('in func1')
    time.sleep(1)


func1 = timmer(func1)
print(func1)
func1()  # 这里的func1是全新的func1,就是上面的赋值,此时相当于执行 inner函数

代码从上至下执行,执行结果:

<function timmer.<locals>.inner at 0x000001552FB00430>
in func1
此函数的执行时间为1.0000975131988525

语法: 想测试谁,前面加@装饰器函数,即可。 写装饰器,约定俗成,函数名为 wrapper

def wrapper(func):
    def inner(*args, **kwargs):
        '''被装饰函数之前'''
        ret = func(*args, **kwargs)
        '''被装饰函数之后'''
        return ret

    return inner


@wrapper
def func(*args, **kwargs):
    print(args, kwargs)
    return 666


print(func())

执行结果:

() {}
666

装饰器利用 return 制造了一个假象,func() 执行,其实是执行 inner() , func() 把原来的 func() 给覆盖了

2 装饰器传参

例 1: 上面装饰器的例子,func1,要传 2 个参数 a,b

import time


def timmer(f):
    def inner(a, b):
        start_time = time.time()
        f(a, b)
        end_time = time.time()
        print('此函数的执行时间为{}'.format(end_time - start_time))

    return inner


@timmer
def func1(a, b):
    print('in func1 {}{}'.format(a, b))
    time.sleep(1)  # 模拟程序逻辑


func1(1, 2)

执行结果

in func1 12
此函数的执行时间为1.0001308917999268

例 2: 如果有多个参数呢?改成动态参数

import time


def timmer(f):
    def inner(*args, **kwargs):
        start_time = time.time()
        f(*args, **kwargs)
        end_time = time.time()
        print('此函数的执行时间为{}'.format(end_time - start_time))

    return inner


@timmer
def func1(*args, **kwargs):
    print('in func1 {}{}'.format(args, kwargs))
    time.sleep(1)  # 模拟程序逻辑


func1(1, 2, a='3', b=4)

执行结果

in func1 (1, 2){'a': '3', 'b': 4}
此函数的执行时间为1.000060796737671

函数的执行时,*打散 ;

函数的定义时,*聚合。

from functools import wraps


def wrapper(f):  # f = func1
    def inner(*args, **kwargs):  # 聚合,args (1,2,3)
        '''执行函数之前的相关操作'''
        ret = f(*args, **kwargs)  # 打散 1,2,3
        '''执行函数之后的相关操作'''
        return ret

    return inner


@wrapper  # func1 = wrapper(func1)  func1 = inner
def func1(*args):  # args (1,2,3) 聚合
    print(666)
    return args


print(func1(*[1, 2, 3]))

执行结果:

666
(1, 2, 3)

例 3:装饰器嵌套

import time  # 1.加载模块


def timmer(*args, **kwargs):  # 2.加载变量  5.接收参数True,2,3
    def wrapper(f):  # 6.加载变量  8.f = func1
        print(args, kwargs)  # 9.接收timmer函数的值True,2,3

        def inner(*args, **kwargs):  # 10.加载变量. 13.执行函数inner
            if flag:  # 14 flag = True
                start_time = time.time()  # 15 获取当前时间
                ret = f(*args, **kwargs)  # 16 执行func1
                time.sleep(0.3)  # 19 等待0.3秒
                end_time = time.time()  # 20 获取当前时间
                print('此函数的执行效率%f' % (end_time - start_time))  # 21 打印差值
            else:
                ret = f(*args, **kwargs)
            return ret  # 22 返回给函数调用者func1()

        return inner  # 11 返回给函数调用者wrapper

    return wrapper  # 7.返回给函数调用timmer(flag,2,3)


flag = True  # 3 加载变量


@timmer(flag, 2, 3)  # 4.执行函数timmer(flag,2,3) 17.执行函数func1 两步:1,timmer(flag,2,3) 相当于执行wrapper  2.@wrapper 装饰器 func1 = wrapper(func1)
def func1(*args, **kwargs):
    return 666  # 18 返回给函数调用者f(*args,**kwargs)


print(func1())  # 12 执行函数

执行结果:

(True, 2, 3) {}
此函数的执行效率0.300905
666

写装饰器,一般嵌套 3 层就可以了

3 多个装饰器,装饰一个函数

def wrapper1(func):  # func ==  f函数名
    def inner1():
        print('wrapper1 ,before func')  # 2
        func()
        print('wrapper1 ,after func')  # 4

    return inner1


def wrapper2(func):  # func == inner1
    def inner2():
        print('wrapper2 ,before func')  # 1
        func()
        print('wrapper2 ,after func')  # 5

    return inner2


@wrapper2  # f = wrapper2(f)  里面的f==inner1  外面的f == inner2
@wrapper1  # f = wrapper1(f)   里面的f==函数名f  外面的f == inner1
def f():  # 3
    print('in f')


f()  # inner2()

执行结果:

wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func

哪个离函数近,哪个先计算。 最底下的先执行
python 函数装饰器_python

4 装饰器的 namedoc_

__name__:函数名
__doc___:函数的解释

4.1 普通函数

def func1():
    """
    此函数是完成登陆的功能,参数分别是...作用。
    return: 返回值是登陆成功与否(True,False)
    """
    print(666)


func1()
print(func1.__name__)  # 获取函数名
print(func1.__doc__)  # 获取函数名注释说明

执行结果

666
func1

    此函数是完成登陆的功能,参数分别是...作用。
    return: 返回值是登陆成功与否(True,False)

这个有什么用呢?比如日志功能,需要打印出谁在什么时间,调用了什么函数,函数是干啥的,花费了多次时间,这个时候,就需要获取函数的有用信息了

4.2 带装饰器的函数

def wrapper(f):  # f = func1
    def inner(*args, **kwargs):  # 聚合, args (1,2,3)
        '''执行函数之前的相关操作'''
        ret = f(*args, **kwargs)  # 打散 1,2,3
        '''执行函数之后的相关操作'''
        return ret

    return inner


@wrapper
def func1():
    """
    此函数是完成登陆的功能,参数分别是...作用。
    return: 返回值是登陆成功与否(True,False)
    """
    print(666)
    return True


func1()
print(func1.__name__)
print(func1.__doc__)

执行结果

666
inner
执行函数之前的相关操作

函数装饰之后,相当于执行了 inner 函数,所以输出 inner

为了解决这个问题,需要调用一个模块 wraps

wraps 将被修饰的函数 (wrapped) 的一些属性值赋值给修饰器函数 (wrapper) ,最终让属性的显示更符合我们的直觉

from functools import wraps


def wrapper(f):  # f = func1
    @wraps(f)  # f是被装饰的函数
    def inner(*args, **kwargs):  # 聚合args (1,2,3)
        '''执行函数之前的相关操作'''
        ret = f(*args, **kwargs)  # 打散 1,2,3
        '''执行函数之后的相关操作'''
        return ret

    return inner


@wrapper
def func1():
    """
    此函数是完成登陆的功能,参数分别是...作用。
    return: 返回值是登陆成功与否(True,False)
    """
    print(666)
    return True


func1()
print(func1.__name__)
print(func1.__doc__)

执行结果

666
func1

    此函数是完成登陆的功能,参数分别是...作用。
    return: 返回值是登陆成功与否(True,False)