0
点赞
收藏
分享

微信扫一扫

Python学习散列:(Decorator)装饰器的使用

A邱凌 2022-01-18 阅读 66

目录

前言

装饰器的概念

装饰器函数的书写

带参数的装饰器

可变参数

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


前言

本来不想写,奈何网上的教程太傻。

其实很多时候写教程都是因为这个原因,到底是怎么做到把这么简单的概念写的乱七八糟的???

装饰器的概念

如果你使用过Django,那你可能已经见过装饰器了,最著名的Django装饰器应该长这样:

@csrf_exempt 

事实上,装饰器仍然是一个函数(其实是函数[函数([函数])]),但它的使用形式如同上图。装饰器的作用是“装饰”一个函数,在使用装饰器之后接的那个函数(下一行的函数)就是被装饰的函数。

装饰器函数的书写

一个最简单的装饰器形如下所示:

def decorator(func):
    def deco_func([args1,args2...]]): #args为参数表,是被修饰函数中的参数,一个不多一个不少
        do_sth
        return func([args1,args2...]) 
    return deco_func

 可以看到,装饰器本身只接受一个参数,那就是被这个装饰器修饰的函数。装饰器中嵌套了另一个函数,由它来接收被修饰函数中的参数表(一个不多一个不少),而被修饰的函数在这个“二级函数”中执行。最后,装饰器将返回二级函数本身。

 不过,并不是所有情况下被修饰的函数都要被执行的,例如如下情况,装饰器在输入函数的参数为1时返回None:

def deco2(func):
    def decor(a):
        if(a==1):
            return None
        else:
            return func(a)
    return decor

@deco2
def funv(a):
    pass

带参数的装饰器

 装饰器当然可以带参数,但在带有参数时,装饰器外面需要再嵌套一层函数用以接收装饰器使用时传入的参数,而在调用时,只需要在调用语句后面加上括号传递参数即可:

def deco3(arg1): #接收装饰器参数
    def deco3_1(func): #接收被装饰函数
        def decor(a,b,c): #接收被装饰函数传入的参数
            print("decorator arg is {0},deco args are {1} {2} {3}.".format(arg1,a,b,c))
            func(a,b,c)
        return decor #逐层返回到最外层
return deco3_1

@deco3("decorator!")
def func(a,b,c):
    print(a+b+c)

可变参数

 很多时候,被修饰的函数和装饰器接收的参数都是不固定的。在这种情况下,我们可以使用*args和**kwargs来读取变化的参数(使用过C系列语言的读者对这两个参数应该不陌生),其中*args传入一个顺序参数的元组(比如func(a,b)则传入(a,b)),**kwargs传入一个指定参数名的参数字典(比如func(a=a1,b=b1)则传入{a=a1,b=b1})。

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

 一个小tips。我通过以下代码以及其运行结果来说明它们的运作顺序:

def deco1(func):
    def decor(a):
        print("before deco1 decorator.")
        func(1)
        print("after deco1 decorator.")
    return decor

def deco2(func):
    def decor(a):
        print("before deco2 decorator.")
        func(2)
        print("after deco2 decorator.")
    return decor

@deco1
@deco2
def func(a):
    print("func run with args: {0}".format(a))

func("") 
#输出如下:
##before deco1 decorator.
    #--第一个装饰器执行前代码先执行
##before deco2 decorator.
    #--第二个装饰器执行前代码后执行
##func run with args: 2
    #--函数体,可以看到调用只有一次,传参是以最后的装饰器为准
##after deco2 decorator.
    #--第一个装饰器执行后代码先执行
##after deco1 decorator.
    #--第二个装饰器执行后代码后执行
举报

相关推荐

0 条评论