python装饰器之原理实现,作用,与例程

装饰器的功能

当需要对一段写好的代码添加一段新的需求的时候的时候我们就可以用装饰器实现。

def set_func(func):
    def call_funct():
        print("---这是权限验证1---")
        print("---这是权限验证2——————")
        func()
    return call_funct

@set_func
def test_1():
    print("----test1----")

test_1()

对test_1函数添加验证1和验证2的功能,需要设计一个闭包,闭包的外部参数传递的是函数的引用,在内部函数里面添加需要添加的功能。比如以上这段代码,我们在test_1函数前面添加上@set_func这个装饰器,在调用test_1函数的时候,我们就会按照call_funct函数里面的顺序执行。

python装饰器之原理实现,作用,与例程_第1张图片

装饰器的原理

def set_func(func):
    def call_funct():
        print("---这是权限验证1---")
        print("---这是权限验证2——————")

        func()
    return call_funct

#@set_func
def test_1():
    print("----test1----")

test_1 = set_func(test_1)
test_1()
#test_1()

装饰器的原理其实就是函数引用的传递,在闭包外部传递函数的引用,内部函数执行完“这是权限验证1”和“这是权限验证2”之后,就会把外部函数传递的函数引用参数拿过来执行

python装饰器之原理实现,作用,与例程_第2张图片
如果把@set_func这个装饰器去掉之后呢
python装饰器之原理实现,作用,与例程_第3张图片
不难理解,因为内部函数执行了两个验证之后,我们的函数的引用是被装饰器修饰过的,所以我们会在执行一下两个验证,最后再执行test_1函数的功能

装饰器统计函数运行时间

import time
def set_func(func):
    def call_funct():
        start_time=time.time()
        func()
        stop_time=time.time()
        print("运行时间是%f"%(start_time-stop_time))
    return call_funct

@set_func
def test_1():
    print("----test1----")
    for i in range(1000):
        pass

test_1()

对有参数无返回值的函数进行修饰

def set_func(func):
    def call_funct(num):
        print("---这是权限验证1---")
        print("---这是权限验证2——————")
        func(num)
    return call_funct

@set_func
def test_1(num):
    print("----test1----%d"%num)

test_1(10000)

对有参数无返回值的参书进行修饰的时候,修饰的函数有几个参数,闭包的内部函数就需要有几个参数,函数地址传递给外部函数,函数实参传递给内部参数
在这里插入图片描述

不定长参数的函数装饰器

可以直接在闭包的内部函数里写不定长参数,当然也可以按照调用函数的形参格式进行传递。

def set_func(func):
    print("开启装饰器")
    def call_func(*args,**kwargs):
        print("11111")
        print("22222")
        func(*args,**kwargs)
    return  call_func

@set_func
def test(num,*args,**kwargs):
    print("test---%d"%num)
    print("test---",args)
    print("test---",kwargs)

test(100)
test(100,200)
test(100,200,300,mm=500)

以上就是按照不定长参数进行传递的。运行结果如下

python装饰器之原理实现,作用,与例程_第4张图片

对带有返回值的函数进行装饰,通用装饰器

首先观察一段错误例程

def set_func(func):
    print("开启装饰器")
    def call_func(*args,**kwargs):
        print("11111")
        print("22222")
        func(*args,**kwargs)
    return  call_func

@set_func
def test(num,*args,**kwargs):
    print("test---%d"%num)
    print("test---",args)
    print("test---",kwargs)
    return "OK"

ret = test(100)
print(ret)

test(100)去调用闭包函数,执行完“开启装饰器 111 222”之后,去执行test函数,test函数有返回值,但是call_func函数没有返回值,所以这个返回值并没有被ret接收到,所以打印出来的结果是None

python装饰器之原理实现,作用,与例程_第5张图片
正确的做法是call_func这个内部函数返回test函数的返回值,正确例程如下:

def set_func(func):
    print("开启装饰器")
    def call_func(*args,**kwargs):
        print("11111")
        print("22222")
        return func(*args,**kwargs)
    return  call_func

@set_func
def test(num,*args,**kwargs):
    print("test---%d"%num)
    print("test---",args)
    print("test---",kwargs)
    return "OK"

ret = test(100)
print(ret)

那么如果被装饰函数没有返回值,但是装饰器有返回值会出现什么情况呢

def set_func(func):
    print("开启装饰器")
    def call_func(*args,**kwargs):
        print("11111")
        print("22222")
        return func(*args,**kwargs)
    return  call_func

@set_func
def test(num,*args,**kwargs):
    print("test---%d"%num)
    print("test---",args)
    print("test---",kwargs)
    return "OK"

@set_func
def a():
    pass

ret = test(100)
print(ret)

ret2=a()
print(ret2)


这个时候ret2会返回None,所有不会对函数有任何影响,故,以上例程的内部函数就是通用装饰器。

多个装饰器对同一个函数进行修饰

def set_func(func):
    print("开启装饰器1111")
    def call_func():
        print("11111")
        return func()
    return  call_func

def add_qx(func):
    print("开启装饰器222")
    def call_func():
        print("222")
        return func()
    return  call_func


@set_func
@add_qx
def test():
    print("----test----")

test()

首先程序是可以执行的,但是执行顺序呢,简单来说,开启装饰器的顺序是从下到上,执行内部函数的时候,由上到下,结果如下:

python装饰器之原理实现,作用,与例程_第6张图片

类的装饰器

class Test(object):
    def __init__(self,func):
        self.func=func

    def __call__(self, *args, **kwargs):
        print("这里是装饰器添加的功能")
        return self.func()

@Test
def get_str():
    return "zhadf"

print(get_str())

运行结果:
python装饰器之原理实现,作用,与例程_第7张图片

装饰器带参数

def set_level(level_num):
    def set_func(func):
        def call_func(*args, **kwargs):
            # level = args[0]
            if level_num == 1:
                print("权限验证1")
            elif level_num == 2:
                print("权限验证2")
            return func()

        return call_func

    return set_func


@set_level(1)
def test1():
    print("test1")
    return "OK"


@set_level(2)
def test2():
    print("test2")
    return "OK"


test1()
test2()

  • 需要在闭包外层再定义一个函数,这个函数用来接受装饰器的参数。效果如上。
    -----------------------------------------------------

  • author:[email protected]

  • github:https://github.com/zhangyuespec/mini_web/tree/master/mini_web框架/装饰器

你可能感兴趣的:(mini_web框架)