在介绍装饰器之前,先了解一下函数调用。
def func():
return "I am func()"
f = func
rst = f()
print(rst)
'''
如果将一个函数赋值给一个参数,那么这个参数就继承了该函数的功能
output: I am func()
'''
最常见的计算函数所用时间
import time
def func():
time.sleep(5)
print("I am func()")
def func1():
start_time = time.time()
time.sleep(5)
print("I am func()")
end_time = time.time()
print(end_time - start_time)
def get_use_time(func):
start_time = time.time()
func()
end_time = time.time()
print(end_time - start_time)
# 方法一:直接修改函数
func1()
# 方法二:利用新的函数来完成
get_use_time(func)
'''
output:
I am func()
5.000549793243408
I am func()
5.000718593597412
'''
为了实现对多个重要的函数方法进行函数所用时间统计,这两种方法就很难实现。于是,便有了装饰器。
简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。
先写一个简单的装饰器:
import time
def test(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print(end_time - start_time)
return wrapper
@test
def func():
print("Hello")
time.sleep(5)
print("I am func()")
func()
'''
output:
Hello
I am func()
5.0007829666137695
'''
接下来看一下有参函数如何使用装饰器
import time
def test(func):
def wrapper(a, b):
start_time = time.time()
func(a, b)
end_time = time.time()
print(end_time - start_time)
return wrapper
@test
def func(a, b):
print("Hello", a, b)
time.sleep(5)
print("I am func()")
func("Hello", "Hello")
'''
output:
Hello Hello Hello
I am func()
5.000677108764648
'''
那么,又有了新的问题,那就是参数的不同就会需要多个装饰器。于是,又有了新的方法。只需要定义一个装饰器就可以对所有函数进行装饰。
import time
def test(func):
def wrapper(*args, **kwargs):
start_time = time.time()
func(*args, **kwargs)
end_time = time.time()
print(end_time - start_time)
return wrapper
@test
def func():
print("Hello")
time.sleep(5)
print("I am func()")
@test
def func1(a, b):
print("Hello", a, b)
time.sleep(5)
print("I am func1()")
@test
def func2(c):
for key,value in c.items():
print(key, value)
time.sleep(5)
print("I am func2()")
func()
func1("Hello", "Hello")
func2({
"Hello": "Ahhhhhh", "hello": "xxxxxxxxxxx"})
'''
output:
Hello
I am func()
5.000675916671753
Hello Hello Hello
I am func1()
5.000266790390015
Hello Ahhhhhh
hello xxxxxxxxxxx
I am func2()
5.000417470932007
'''
除了上面的一个装饰器需要装饰多个函数以外,有时候还需要用多个函数来装饰一个函数。我们知道一个装饰器装饰函数是先执行装饰器再执行函数本身。那么多个装饰器又是怎么执行的呢?
装饰器是先从被调函数开始看,如果被装饰,就执行装饰函数直到遇到包裹函数,如果包裹函数也被装饰,就再执行上层装饰函数,循环下去,直到没有上层装饰器,然后再从最上层装饰执行下去。
import time
def test1(func):
print("test1---------decorator")
def wrapper(*args, **kwargs):
print("test1---------begin")
func(*args, **kwargs)
print("test1---------end")
return wrapper
def test2(func):
print("test2---------decorator")
def wrapper(*args, **kwargs):
print("test2---------begin")
func(*args, **kwargs)
print("test2---------end")
return wrapper
def test3(func):
print("test3---------decorator")
def wrapper(*args, **kwargs):
print("test3---------begin")
func(*args, **kwargs)
print("test3---------end")
return wrapper
@test1
@test2
@test3
def func():
print("Hello")
time.sleep(5)
print("I am func()")
func()
'''
output:
test3---------decorator
test2---------decorator
test1---------decorator
test1---------begin
test2---------begin
test3---------begin
Hello
I am func()
test3---------end
test2---------end
test1---------end
'''
最后的最后补充一点:装饰器的参数不一定是函数,但返回值一定是一个函数(包裹函数),而且包裹函数与原函数参数必须一致
def deco(x):
print("deco")
def wrapper(f):
print("wrapper()中的f:%s" %f.__name__)
return f
return wrapper
@deco(3)
def func(tes):
print("func()中的值:%d"% tes.test)
class Test:
def __init__(self):
self.test = 5
tes = Test()
func(tes)
'''
output:
deco
wrapper()中的f:func
func()中的值:5
'''
结束之前呢,给大家补充一下面试中问到装饰器的标准答案(仅供参考)~
场景一(比较委婉):
Q:我看你简历一般用python?
A:对!
Q:那你给我简单介绍一下python中的装饰器吧。
A:额,装饰器啊,就像装修房子似的。emmm,其实我也没用过。
场景二(也可以直接一点):
Q:我看你简历一般用python?
A:对!
Q:那你给我简单介绍一下python中的装饰器吧。
A:装饰器啊,不知道!不会!