装饰器是Python中很重要的一个功能, 一句话总结装饰器就是: 将被装饰函数作为参数传入装饰函数中, 并实现装饰函数中的多余功能.
下面一一说明什么是装饰器:
def f1():
print("Called f1")
print(f1)
<function f1 at 0x7fd2b87b8040>
我们定义了一个f1函数, 然后打印f1 显示的是这个函数的储存地址, 也就是说 function 在python 中是个 object, 可以作为参数传入 另一个function中.
def f2(f):
f()
f2(f1)
output:
Called f1
我们定义如下函数:
def f1(func):
def wrapper():
print("Start")
func()
print("End")
return wrapper
def f():
print("Hello")
将f 作为参数传入f1中:
f1(f)
output:
<function __main__.f1.<locals>.wrapper()>
输入为 一个function. 因为f1返回的是 wrapper函数. 并没有调用wrapper函数. 下面调用wrapper函数:
f1(f)()
输出:
Start
Hello
End
也可以赋值给新的变量:
f = f1(f)
f()
输入:
Start
Hello
End
这就是装饰器了. f为被装饰函数, 它被传入了装饰函数f1中, 并有了f1函数内部的功能. 用装饰器的写法就是:
@f1
def f():
print("Hello")
f()
输出:
Start
Hello
End
但到这里 被装饰函数中没有参数, 如果传入参数 会产生error:
f("hi")
output:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Input In [39], in <cell line: 1>()
----> 1 f("hi")
TypeError: wrapper() takes 0 positional arguments but 1 was given
如果想在被装饰函数中可传入参数的话, 可以如下这样修改装饰器:
def f1(func):
def wrapper(*args, **kwargs):
print("Start")
func(*args, **kwargs)
print("End")
return wrapper
让wrapper可以传入任何形式的参数
@f1
def f(a, b=9):
print(a, b)
f(3)
输出:
Start
3 9
End
到这里 被装饰的函数都是print()的形式, 如果是return 的形式, 可以 在wrapper函数中加入return:
def f1(func):
def wrapper(*args, **kwargs):
print("Start")
val = func(*args, **kwargs)
print("End")
return val
return wrapper
@f1
def add(x, y):
return x + y
print(add(4,5))
输入:
Start
End
9
总结, 建立一个装饰器, 给 被装饰函数 赋予可以输处 被装饰函数运行时间的功能:
import time
def timer(func):
def wrapper():
before = time.time()
func()
print("Function took:", time.time() - before, "seconds")
return wrapper
@timer
def run():
time.sleep(2)
run()
输出:
Function took: 2.005012035369873 seconds