装饰器实质是函数,只是应用较广,所以就直接叫做装饰器,又叫做语法糖
一、闭包的概念
def func():
var = 'hello,world'
print(var)
def inner():
var = 'GitHub'
print(var)
# 执行
func()
这个里面包含两个知识点,一是函数名其实也是一种变量,func这个函数名指向其所对应的函数封装内容,而在func函数中,又在内定义了一个inner函数。
函数定义后通过 函数名 + () 有的需要传入参数)调用,而此处调用的是func()函数,先赋值变量var,输出,再定义函数inner(),但inner函数并没有被调用,所以打印的结果是hello,world
如下图:
那怎么样才能调用inner呢?
先试试直接调用
inner()
这会出错,说变量 inner 未被定义,这很好理解,因为 inner 这个函数名本身就是一个变量,那么就可以知道它是局部变量,只在 func() 内起作用。所以这个 inner() 函数就是一个闭包,它在func() 外不能被直接访问。
那到底该怎么做呢?
我们可以通过返回值来调用inner(),具体如下:
def func():
var = 'hello,world'
print(var)
def inner():
var = 'GitHub'
print(var)
return inner
i = func()
i()
print("func:{} , inner:{}".format(func,i))
可以看到此次输出了 GitHub,这是因为func,inner都是变量,指向其所代表的函数。那么将返回值 inner 其所指向的地址赋值给另一个变量i,再通过 i() 就能访问到闭包 inner() 。
装饰器本质上就是一个闭包。
二、装饰器
顾名思义,装饰器就是用来修饰某个函数,在不改变原来方法代码和调用方式的前提下,额外的附加其他的功能和属性。
先来看个例子
def timer(func):
def inner(): # 闭包函数
func()
print('Hello,world')
return inner
def fun1():
print('GitHub')
fun2 = timer(fun1)
fun2()
fun1 = timer(fun1)
fun1()
具体过程是先以 fun1 为参数 调用 timer() 返回 inner ,并赋值给名为 fun2 的变量,再用fun2 + () 去调用 inner 所指向的闭包,若把 fun2 换成 fun1,则我们实现了不改变一个函数的代码,给一个函数增加功能但不改变其调用方式。
现在来修改一下
def timer(func):
def inner():
func()
print('Hello,world')
return inner
@timer
def fun1():
print('GitHub')
fun1()
可以看到这里,调用fun1() 在结果中也打印出了 Hello,world ,所以 @timer 的作用等效于 fun1 = timer(fun1) ,即把 fun1作为参数传递给装饰器 timer() ,返回闭包函数名所指向的地址给 fun1,最后再通过fun1 调用。
更进一步,还可以新建一个新文件,导入刚才的模块,如下
from sfd import fun1 # sfd 是我刚才写入代码的文件名
fun1()
结果不变
除此之外,多个装饰器也可以装饰同一个函数。