欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python中装饰器(Decorator)的理解

程序员文章站 2022-03-10 16:09:10
...

之前经常看到‘@’这个符号在代码里出现,后来才知道这是装饰器,借这个机会,看了一些博客,写了一些demo,记录一下浅显的理解

语法糖(Syntactic sugar)

由英国计算机科学家Peter.J.Landin发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。(这段来自百度)
语法糖的存在是为了方便开发人员进行代码的编写,加了糖后的代码块与加糖前相比,运行完全等价,但结构却更加简单,代码更加简洁。
一个Python中的例子:列表生成式

#普通生成一个1至10的列表
test_list = []
for i in range(10):
	test_list.append(i)

#列表生成式
test_list = [i for i in range(10)]

所得结果都是一样的,但是使用列表生成式的代码更加简洁流畅。

装饰器(Decorator)

首先引入闭包的概念,闭包(Closure)可以简单理解为一个定义在函数中的子函数,它可以作为函数与外界沟通的桥梁,使得定义在函数中的局部变量在脱离这个上下文后仍然得以存在。
一个例子:

#闭包
def msg():
    t = "Decorator Test"
    def Closure():
        print(t)
    return Closure
   

demo = msg()
demo()

#运行结果
Decorator Test

可以看到,在外层函数msg()函数被调用后,其生存期已结束,但我们仍然可以通过demo调用获取其中的变量t.
装饰器中的核心内容就是闭包。
装饰器使用语法:
使用@符号加装饰器名字,然后再定义需要使用的函数。
装饰器最强大的作用就是使用很简单的一个语法就可以在不侵入核心代码的前提下给被装饰函数加上功能(语法糖)

无参数装饰器

正如上文所说,装饰器最核心的部分就是闭包的实现,它帮助我们增强函数的功能,因此闭包与我们被装饰的函数息息相关。
先是最基础的函数,没有参数,仅打印一行消息:

#基础装饰器
def msg(test):
    t = "Decorator Test"
    def Closure():
        test()
        print(t)
    return Closure

#装饰器的使用
@msg
def test():
    print("This is a",end=' ')

test()
#运行结果
This is a Decorator Test

可以看到,我们定义一个装饰器实际上就是定义了一个有闭包的函数,它接受我们被装饰的函数为参数,随后在闭包中进行加工,然后我们通过闭包的调用实现更强的功能。

多参数的装饰器

当然,更为常见的是多参数的函数,要注意的是,闭包的接受参数要能与被装饰的函数匹配。
可变参数的装饰器例子:

#不定参数的装饰器
def dec(test):
    t = "Boom!!!"
    def count(*arg,**kwargs):
        test(*arg,**kwargs)
        print(t)
    return count
   
#运行示例1
@dec
def func1(a,b):
    print("%d! %d!"%(a, b),end=" ")

func(2,1)
#运行结果
2! 1! Boom!!!

#运行示例2
@dec
def func2(a,b,c,d):
    print("%d! %d! %d! %d!"%(a, b, c, d),end=" ")
 
func2(4,3,2,1)
#运行结果
4! 3! 2! 1! Boom!!!

多装饰器

当然可以用多个装饰器去装饰同一个函数,这里的装饰形成一种嵌套关系在多行的@装饰器中,最外层的装饰器功能最先执行。
一个例子:

#多装饰器
def fun_1(func):
    t_1 = "The first Bomb!!"
    def dec_1(*arg,**kwargs):
        print(t_1)
        func(*arg,**kwargs)
        print("You Died!!")
    return dec_1
    
def fun_2(func):
    t_2 = "The Second Bomb!!"
    def dec_2(*arg,**kwargs):
        print(t_2)
        func(*arg,**kwargs)
        print("You Died!! Again!!!")
    return dec_2
   
@fun_2
@fun_1 
def fun(a,b,c,d):
    print("%d! %d! %d! %d!"%(a, b, c, d))
fun(4,3,2,1)
#运行结果
The Second Bomb!!
The first Bomb!!
4! 3! 2! 1!
You Died!!
You Died!! Again!!!

可以看到,多个装饰器的使用就是以嵌套的关系实现的。

装饰器的返回值

当需要取回被装饰函数的返回值时,需要手动设置一个变量存储返回值,否则调用函数会返回一个NoneType
代码示例:

#返回值测试1
def msg(test):
    def closure():
        print("The test of",end=' ')
        test()
    return closure
   
@msg
def test():
    return "return_value"
 
k = test()
print(type(k))

#运行结果
The test of 
NoneType

#返回值测试2
#返回值测试
def msg(test):
    def closure():
        print("The test of",end=' ')
        val = test()
        return val
    return closure

@msg
def test():
    return "return_value"

k = test()
print(k)

#运行结果
The test of return_value

可以看到,没有用变量存储返回值时,我们没法得到返回值,是一个NoneType加上变量后,能够取回被装饰函数的返回值。
以上是浏览了几篇博客,做了一些小测试后的认知,以后若深入学习再回来更新。

相关标签: Python相关