什么是装饰器
Python中的装饰器是一个特殊的函数,它用来修饰我们定义的普通函数,使其在调用前后增加额外功能而不需要修改原代码。装饰器的本质目的是美化精简代码,当然这种操作能让代码维护起来更方便。
实质:是一个函数
参数:是需要修饰的函数名(Python中一切皆对象,函数也可以作为参数 传递。函数名非函数调用)
返回:是修饰完的函数名(非函数调用)
作用:为已经定义的函数增加额外功能
特点:不需要被修饰的函数做代码上的修改
它的应用场景多在插入日志、性能测试、事务处理、权限校验等。
前言
Python中函数内可以再定义函数
举个例子:
def outside():
def inside():
print("*********")
inside()
outside()
这里需要注意的是,内部函数inside只能在外部函数outside里被调用,在其外是不能被调用的。
Python中一切皆对象,函数本身也可以作为参数传递
举个例子:
def outside(function):
def inside():
print("*********")
function()
inside()
def say_hello():
print("hello")
outside(say_hello)
这里需要注意的是,当把函数作为参数传递的时候,一定是传递的函数名,即say_hello而不是say_hello()。加了括号表示函数调用,即函数会立即执行一次。
从函数中返回一个函数
举个例子:
def outside(function):
def inside():
print("*********")
return function
return inside
def say_hello():
print("hello")
outside(say_hello)()()
这里outside函数内部两个return返回的是函数名即没有加“()”。最后一行函数调用代码,第一个括弧表示传参并执行outside函数,第二个括弧表示调用outside函数返回的inside函数,第三个括弧表示调用inside函数返回的function即我们的参数say_hello函数。
进入正题
模拟一个场景。我们做了一个项目,里面有很多定义的函数,为了后期好维护,现在的需求是要给每个函数打log,在函数被调用的时候输出一行字记录函数调用情况。之前也许我们会这么写代码:
def say_hello():
print("hello")
# 记录调用情况
print("say_hello函数被调用")
def say_happy():
print("happy")
# 记录调用情况
print("say_happy函数被调用")
这样可以达到目的,不过显得有点呆,代码工作量很大。而且三条记录调用情况的代码看起来差不多,很重复,如果有办法能获取到函数名字的话,包装成一个函数调用可能相对好一些。
基于我们前言讲的东西,可以改进我们的代码。
def log(function):
def wrap():
print("{}函数被调用".format(function.__name__))
return function()
return wrap
def say_hello():
print("hello")
def say_happy():
print("happy")
'''
下面代码等价于先接收返回值wrap函数名,在加上()调用这个函数
x = log(say_hello)
x()
'''
log(say_hello)()
log(say_happy)()
我们写的这个log函数其实就是一个装饰器。用@的方式表现出来是这样子的:
def log(function):
def wrap():
print("{}函数被调用".format(function.__name__))
return function()
return wrap
@log
def say_hello():
print("hello")
@log
def say_happy():
print("happy")
say_hello()
say_happy()
log函数里面的代码可能有些小伙伴会有疑虑说return wrap去调用感觉很重复。能不能删掉第2行和第5行代码,只在log函数里面写print和return function()两行代码。不可以,程序会报错!