概述
装饰器(decorators)是Python的一个重要的部分,简单的介绍,函数装饰器是修改其他函数的功能的函数,有助于代码更加的简洁,也更有Python范。
函数皆是对象
首先,需要理解在Python中,函数也是对象。比如如下的代码:
def hi(name="yasoob"):
return "hi " + name
print(hi())
#输出:'hi yasoob'
#可以将一个函数名赋值给一个变量。注意只是函数名func,而不是func()的形式
greet = hi
print(greet())
#输出:'hi yasoob'
#如果删除掉旧的函数名hi,但是不影响新的函数名greet,因为本质上hi与greet只是保存函数地址的变量
#只要函数地址是有效的,则均可以通过变量保存的函数名来调用函数
del hi
print(hi())
#输出:NameError
print(greet())
#输出:'hi yasoob'
在函数中定义函数
在Python中,可以在函数中定义另一个函数,也就是可以创建嵌套的函数:
def hi(name="yasoob"):
print("now you are inside the hi() function")
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
print(greet())
print(welcome())
print("now you are back in the hi() function")
hi()
#调用函数hi,输出结果为:
#'now you are inside the hi() function'
#'now you are in the greet() function'
#'now you are in the welcome() function'
#'now you are back in the hi() function'
#以上的结果显示了在调用hi()时,函数greet()和welcome()都将被调用
#但是函数greet()和welcome()是在函数hi()内部定义的,在hi()函数外部是不能访问的。
greet()
#输出:NameError: name 'greet' is not defined
从函数中返回函数
在Python中,也可以将一个函数名作为输出返回。
def hi(name="yasoob"):
def greet():
return "now you are in the greet() function"
def welcome():
return "now you are in the welcome() function"
if name == "yasoob":
return greet
else:
return welcome
a = hi()
print(a)
#输出:<function greet at 0x7f2143c01500>
#这里的输出显示了变量a保存的是函数内部定义的greet()函数地址,因此a()即可调用greet()函数
print(a())
#输出:'now you are in the greet() function'
注意,在以上代码中,hi函数返回的是 return greet 与 return welcome,而不是 return greet() 与 return welcome(),这里返回的应该是函数名,而不是函数调用,带或者不带括号,是有很大区别的,若返回的是 return greet() ,表示返回的是函数greet执行的结果,而不是返回greet这个函数地址。
将函数作为参数传递给另一个函数
函数的入参可以为普通的变量,也可以为函数名,因为根据以上的知识介绍,函数也是对象,因此函数名也是函数这个对象的引用,如下的实例代码:
def hi():
return "hi yasoob"
def doSomethingBeforeHi(func):
print("i am doing some boring work before executing hi()")
print(func())
doSomethingBeforeHi(hi)
#输出:
#'i am doing some boring work before executing hi()'
#'hi yasoob'
函数装饰器
根据以上介绍的知识,可以创建一个函数装饰器了,范例代码如下:
def a_new_decorator(a_func):
def wrapTheFunction():
print("i am doing some boring work before executing a_func()")
a_func()
print("i am doing some boring work after executing a_func()")
return wrapTheFunction
def a_function_requiring_decoration():
print("i am the function which needs some decoration to remove")
a_function_requiring_decoration()
#输出:'i am the function which needs some decoration to remove'
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#这里a_new_decorator函数的入参为函数名a_function_requiring_decoration,
#因此入参为旧的函数a_function_requiring_decoration
#所以在a_new_decorator里定义的wrapTheFunction,将执行a_func(),执行的是旧的函数
#a_new_decorator返回return wrapTheFunction,
#因此变量a_function_requiring_decoration现在指向的是wrapTheFunction函数,而不是原来旧的函数
#注意这里没有print语句被执行到,因为a_new_decorator函数内嵌函数只是定义,不会被执行
#执行的只是return wrapTheFunction这一条语句
a_function_requiring_decoration()
#输出:
#'i am doing some boring work before executing a_func()'
#'i am the function which needs some decoration to remove'
#'i am doing some boring work after executing a_func()'
以上的代码并没有使用到@符号,但是使用@符号只是生成被装饰的函数的简短的方式。原理是一样的。使用@符号生成函数装饰器的代码范例:
@a_new_decorator
def a_function_requiring_decoration():
print("i am the function which needs some decoration to remove")
a_function_requiring_decoration()
#输出:
#'i am doing some boring work before executing a_func()'
#'i am the function which needs some decoration to remove'
#'i am doing some boring work after executing a_func()'
#通过以上的代码可知,@a_new_decorator是以下代码的简短表达方式:
#a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
print(a_function_requiring_decoration.__name__)
#输出:wrapTheFunction
#这里可以看出,变量a_function_requiring_decoration指向的不再是原来的函数,而是内嵌定义的函数
#但是有时候我们希望变量还是指向原来的函数,但是这个函数被内嵌函数的行为重新定义。
#python提供了functools.wraps函数来解决这个问题
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("i am doing some boring work before executing a_func()")
a_func()
print("i am doing some boring work after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
print("i am the function which needs some decoration to remove")
print(a_function_requiring_decoration.__name__)
#输出:a_function_requiring_decoration
#@wraps接受一个函数进行装饰,并加入了复制函数的名称,注释文档,参数列表等
#这样可以使得在装饰器里面访问在装饰之前的函数的属性
另一范例
使用函数装饰器的另一段代码范例:
from functools import wraps
def decorator_name(func):
@wraps(func)
def decorated(*args, **kwargs):
if not can_run:
return "function will not run"
return func(*args, **kwargs)
return decorated
@decorator_name
def func():
return "function is running"
can_run = True
print(func())
#输出:'function is running'
can_run = False
print(func())
#输出:'function will not run'
来源:CSDN
作者:篡篡
链接:https://blog.csdn.net/jiangzhangha/article/details/103744358