令人疑惑的装饰器
Python 里面测语法糖太多,装饰器是其中一个,用到了闭包的原理。
个人感觉最大测作用就是节省代码
最简单的例子
# 定义一个简单的装饰器
def simple_decorator(func): # 传入一个函数作为参数
# 包装原始函数的内部函数
def wrapper():
print("即将执行函数...")
func() # 执行原始函数
print("函数执行完毕。")
return wrapper
# 使用装饰器
@simple_decorator
def greet():
print("被修饰的函数:你好!")
# 调用被装饰的函数
greet()
例子1 不带参数的装饰器
import time
import random
def timer(func):
def decorated(*args, **kwargs):
st = time.time()
ret = func(*args, **kwargs)
print("time cost: {} seconds".format(time.time() - st))
return ret
return decorated
@timer
def random_sleep():
time.sleep(random.randint(0,5))
random_sleep()
# >>> time cost: 2.0021181106567383 seconds
例子2 带参数的装饰器,相当于包了两层
def timer(print_args):
def decorator(func):
def wrapper(*args, **kwargs):
st = time.time()
ret = func(*args, **kwargs)
if print_args:
print(f"{func.__name__}, args: {args}, kwargs: {kwargs}")
print("time cost: {} seconds".format(time.time() - st))
return ret
return wrapper
return decorator
@timer(print_args=True)
def random_sleep():
time.sleep(random.randint(0,5))
random_sleep()
# >>> random_sleep, args: (), kwargs: {}
# time cost: 9.34600830078125e-05 seconds
例子3 用类实现装饰器(函数替换)
class timer:
def __init__(self, print_args):
self.print_args = print_args
def __call__(self, func):
def decorator(*args, **kwargs):
st = time.time()
ret = func(*args, **kwargs)
if self.print_args:
print(f"{func.__name__}, args: {args}, kwargs: {kwargs}")
print("time cost: {} seconds".format(time.time() - st))
return ret
return decorator
@timer(print_args=True)
def random_sleep():
time.sleep(random.randint(0,5))
random_sleep()
>>> random_sleep, args: (), kwargs: {}
time cost: 5.004449367523193 seconds
例子4 用类实现装饰器(实例替换)
class DelayedStart:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
time.sleep(1)
print("wait for 1 second")
return self.func(*args, **kwargs)
def eager_call(self, *args, **kwargs):
print("call without delay")
return self.func(*args, **kwargs)
# demo已经变成DelayedStart的一个实例,等同于 demo = DelayedStart()
@DelayedStart
def demo():
print("hello world")
# 相当于调用__call__方法
# demo()
# 调用额外方法
# demo.eager_call()
装饰器的应用场景
通过上述分析,我们可以看到,装饰器似乎提供了一种动态修改或者说加强函数的能力,通过使用装饰器,你可以在原函数的基础上增加一些逻辑,最大的用处是节省代码。
那装饰器主要可以用在哪些场景呢