装饰器

Posted wanglan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰器相关的知识,希望对你有一定的参考价值。

装饰器的功能:在不修改原函数和其调用方式的情况下对原函数功能进行扩展

装饰器的本质是闭包函数

求一个函数的运行时间

import time
def func():
    start = time.time()
    print(老板好!同事好!大家好!)
    time.sleep(0.01)
    end = time.time()
    print(end-start )
func()

但是有多个函数都需要添加此功能时,就会显得很繁琐,此时可以写一个时间函数

import time


def timer(f):
    start = time.time()
    f()
    time.sleep(0.01)
    end = time.time()
    print(end - start)


def func():
    print(老板好!同事好!大家好!)


timer(func)

这样不管多少函数都可以调用这个时间函数来计算执行的时间了,但是这样改变了函数的调用方式,原本调用func函数的程序现在要改为调用timer了

import time


def timer(f):
    start = time.time()
    f()
    time.sleep(0.01)
    end = time.time()
    print(end - start)


def func():
    print(老板好!同事好!大家好!)


func = timer  
func()          

这样修改很完美,但是timer函数需要一个参数,如果在赋值的时候传参, func = timer(func),timer函数就直接执行了,并不能实现

简单的装饰器实现上面的功能

import time


def timer(f):    #装饰器函数
    def inner():
        start = time.time()
        f()  #被装饰的函数
        time.sleep(0.01)
        end = time.time()
        print(end - start)
    return inner

def func():
    print(老板好!同事好!大家好!)


func = timer(func)
func()

语法糖

import time


def timer(f):
    def inner():
        start = time.time()
        f()
        time.sleep(0.01)
        end = time.time()
        print(end - start)

    return inner


@timer  # 语法糖 相当于func = timer(func)
def func():
    print(老板好!同事好!大家好!)


# func = timer(func)
func()

被装饰的函数有返回值

import time


def timer(f):
    def inner():
        start = time.time()
        ret = f()
        time.sleep( 0.01)
        end = time.time()
        print(end - start)
        return ret

    return inner


@timer  # 语法糖 相当于func = timer(func)
def func():
    print(老板好!同事好!大家好!)
    return 新年好


# func = timer(func)
ret = func()
print(ret)

带有参数的被装饰的函数

import time


def timer(f):
    def inner(*args,**kwargs):
        start = time.time()
        ret = f(*args,**kwargs)
        time.sleep( 0.01)
        end = time.time()
        print(end - start)
        return ret

    return inner


@timer  # 语法糖 相当于func = timer(func)
def func(a,b,c):
    print(老板好!同事好!大家好!,a,b,c)
    return 新年好


# func = timer(func)
ret = func(1,2,c=3)  #inner
print(ret)

装饰器的固定模式

def wrapper(f):  # f :被装饰的函数
    def inner(*args, **kwargs):
        # 在被装饰函数之前要做的事
        ret = f(*args, **kwargs)
        # 在被装饰函数之后要做的事
        return ret

    return inner


@wrapper  # 语法糖 @装饰器的函数名
def func(a, b, c):  # 被装饰的函数
    print(a, b, c)
    return 新年好


ret = func(1, 2, c=3)
print(ret)

查看函数信息的一些方法

def index():
    ‘‘‘这是一个主页信息‘‘‘
    print(from index)

print(index.__doc__)    #查看函数注释的方法
print(index.__name__)   #查看函数名的方法

查看函数的信息

为函数添加了装饰器,在打印被装饰函数的__name__或__doc__的时候,打印的是装饰器的

def wrapper(f):  # f :被装饰的函数
    def inner(*args, **kwargs):
        # 在被装饰函数之前要做的事
        ret = f(*args, **kwargs)
        # 在被装饰函数之后要做的事
        return ret

    return inner


@wrapper  # 语法糖 @装饰器的函数名
def func(a, b, c):  # 被装饰的函数
    print(a, b, c)
    return 新年好

print(func.__name__)

打印结果:
inner

想要打印被装饰的函数__name__或__doc__,可以使用wraps装饰器

from functools import wraps
def wrapper(f):  # f :被装饰的函数
    @wraps(f) #f:被装饰的函数
    def inner(*args, **kwargs):
        # 在被装饰函数之前要做的事
        ret = f(*args, **kwargs)
        # 在被装饰函数之后要做的事
        return ret

    return inner


@wrapper  # 语法糖 @装饰器的函数名
def func(a, b, c):  # 被装饰的函数
    print(a, b, c)
    return 新年好

print(func.__name__)

打印结果:
func

带参数的装饰器

import time
FLAG = True
def timer_out(flag):
    def timer(func):
        def inner(*args, **kwargs):
            if flag:
                start = time.time()
                ret = func(*args, **kwargs)
                end = time.time()
                print(end - start)
                return ret
            else:
                ret = func(*args, **kwargs)
                return ret

        return inner

    return timer


@timer_out(FLAG)
def beibingyang():
    time.sleep(0.1)
    print(beibingyang)


@timer_out(FLAG)
def erguotou():
    time.sleep(0.1)
    print(erguotou)


beibingyang()
erguotou()

@timer_out(FLAG) 分为两部分:

@:为一部分  

timer_out(FLAG):为一部分

timer_out(FLAG)执行时返回inner,此时@timer_out(FLAG)为@inner

@inner 为 beibingyang= timmer(beibingyang)

当FLAG改为False装饰器就失效了,这样添加和取消都比较便捷

 

多个装饰器装饰同一个函数

def wrapper1(func): #第一步执行后 func=f
    def inner1():
        print(wrapper1 ,before func) #第六步 输出 wrapper1 ,before func
        func() #第七步 调用 f
        print(wrapper1 ,after func) #第八步 输出 wrapper1 ,before func
    return inner1

def wrapper2(func): #第二部执行后 func=inner1
    def inner2():
        print(wrapper2 ,before func) # 第四步 输出 wrapper2 ,before func
        func() #第五部 调用inner1
        print(wrapper2 ,after func) #第九步 输出 wrapper2 ,before func
    return inner2

@wrapper2 #第二步执行 f=wrapper2(f)  返回inner2 f=inner2
@wrapper1 #第一步执行 f=wrapper1(f) 返回 inner1 f=inner1
def f():
    print(in f)

f() #第三步执行 f() 此时f为inner2 调用inner2

打印结果

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

 

以上是关于装饰器的主要内容,如果未能解决你的问题,请参考以下文章

Python面向对象学习之八,装饰器

thymeleaf 片段渲染后重新加载 javascript

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码

代码缺乏装饰?使用ts装饰器来装饰你的代码