Python Decotator

装饰器(decorators)是 Python 中的一种高级功能,它允许你动态地修改函数或类的行为。
装饰器是一种函数,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数。
装饰器的语法使用 @decorator_name 来应用在函数或方法上。
Python 还提供了一些内置的装饰器,比如 @staticmethod 和 @classmethod,用于定义静态方法和类方法。
装饰器的应用场景:
- 日志记录: 装饰器可用于记录函数的调用信息、参数和返回值。
- 性能分析: 可以使用装饰器来测量函数的执行时间。
- 权限控制: 装饰器可用于限制对某些函数的访问权限。
- 缓存: 装饰器可用于实现函数结果的缓存,以提高性能。
我们先看下面这个例子,我们对hello()进行一些包装,实现一个记录函数运行时间的方法。
1 2 3 4 5 6 7
| def timing(f): return f def hello(): print("Hello World") hello = timing(hello) hello()
|
上面的这个例子我们调用timing,实际上返回的还是hello这个函数的,其实什么都没有做。在实际业务中,我们希望timing返回一个新的函数,调用新函数就相当于调用了hello,开发中习惯叫这个新函数wrapper。
1 2 3 4 5 6 7 8 9 10 11 12
| def timing(f): def wrapper(): return f return wrapper
def hello(): print("Hello World")
hello = timing(hello)
print(hello) hello()
|
我们简单实现以下函数计时器的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import time
def timing(f): def wrapper(): start_time = time.time() result = f() end_time = time.time() print(f"Total time => {end_time - start_time}") return result
return wrapper
def hello(): print("Hello World")
hello = timing(hello) hello()
|
到此实际上我们已经实现了装饰器的功能,但这种写法有点奇怪,我们可以使用Python的语法糖来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import time
def timing(f): def wrapper(): start_time = time.time() result = f() end_time = time.time() print(f"Total time => {end_time - start_time}") return result
return wrapper
@timing def hello(): print("Hello World")
hello()
|
装饰器的参数处理
上面的例子是没有参数的情况,正常的业务处理中我们会面对各种各样的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import time
def timing(f): def wrapper(*args, **kwargs): start_time = time.time() result = f(*args, **kwargs) end_time = time.time() print(f"Total time => {end_time - start_time}") return result
return wrapper
@timing def hello(): print("Hello World")
@timing def hello_one(name): print(f"Hello, {name}")
hello() hello_one("John", "Tom")
|
我们可以在wrapper上加入可变参数,这样就可以适配所有的参数场景。
修饰类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import time
def timing(f): def wrapper(*args, **kwargs): start_time = time.time() result = f(*args, **kwargs) end_time = time.time() print(f"Total time => {end_time - start_time}") return result
return wrapper
@timing class Foo: def __init__(self): pass
Foo()
|
上面的代码创建 Foo() 实例时,装饰器 @timing 会记录类的构造函数执行所需的时间。因此,打印出来的时间表示了调用 Foo() 实例化对象的时间消耗。