装饰器:不修改代码,就能改变函数功能的强大特性
我们可以将函数作为参数传递到函数中,一个简单的例子:
def sqare(x):
return x*x
def print_running(f,x):
print(f'{f.__name__} is running.')
return f(x)
result = print_running(sqare,2)
print(result)
通过这个例子,我们就可以理解将函数作为参数传递到函数中这件事情了.下面进入今天的主题:装饰器.
装饰器本质上是一个函数,它会接受函数作为参数,在自己内部,根据这个传入的函数定义一个新函数,新函数在包含传入函数功能的同时扩充了其他的功能
然后装饰器将新函数返回,我们就可以在代码里使用这个返回的新函数了替代原来的传入函数了.
看一个简单的例子:
import time
def square(x):
return x*x
def decorater(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f'{func.__name__} executed in {round(end_time - start_time, 2)} seconds.')
return result
return wrapper
decorated_square = decorater(square)
decorated_square(10)
实际上Python提供了一个更简单的方法来使用装饰器,就是给函数定义戴个帽子
@decorater
def square(x):
return x*x
square(10)
我们还可以定义一个定义装饰器的函数,在这里先叫做装饰器生成器
装饰器生成器会根据参数生成不同的装饰器
def timer(threshold):
def decorater(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
if end_time-start_time > threshold:
print(f'{func.__name__} took longer than {threshold} seconds.')
return result
return wrapper
return decorater
@timer(0.2)
def sleep_04():
time.sleep(0.4)
sleep_04()
如果要打印sleep_04.__name__
会发现打印出来的是"wrapper
"
因为wrapper
我们是想要代替原来的func,因此我们是希望wrapper
可以继承func
的属性,我们可以在wapper上面加一行@functools.wraps(func)
这个是Python中已经定义好的,所以还要引入:import functools
,这样打印出来的名字就是它原来的名字了.
那装饰器到底有什么好处?