Python装饰器:优雅地增强函数功能
在Python开发中,我们常常需要在已有函数上增加日志、计时、权限校验等额外功能。如果直接修改函数代码,不仅破坏开闭原则,还会导致重复代码。装饰器(Decorator)正是解决这一问题的利器——它让你在不改动函数源码的前提下,为函数“穿上”新的能力。
装饰器本质:函数也是对象
装饰器本质上是一个可调用对象(通常是函数),它接收一个函数作为参数,并返回一个新的函数。来看一个最简单的例子:
def logger(func):
def wrapper(*args, **kwargs):
print(f"调用函数:{func.__name__}")
return func(*args, **kwargs)
return wrapper
def add(x, y):
return x + y
# 手动装饰
add = logger(add)
Python提供的@语法糖让这个过程更加直观:
@logger
def add(x, y):
return x + y
实战:计时装饰器
假设我们需要测量多个函数的执行时间,写一个计时装饰器可以一劳永逸:
import time
from functools import wraps
def timer(func):
@wraps(func) # 保留原函数的元信息
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} 耗时:{end - start:.4f}秒")
return result
return wrapper
@timer
def slow_task():
time.sleep(1)
return "完成"
slow_task() # 输出:slow_task 耗时:1.0002秒
这里使用了functools.wraps,它能将原函数的__name__、__doc__等属性复制到包装函数上,避免调试时混淆。
带参数的装饰器
有时我们希望装饰器本身接收参数,只需再嵌套一层:
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(times=3)
def greet():
print("你好!")
greet() # 打印三次“你好!”
总结
装饰器是Python“语法糖”中的典范,它基于闭包和高阶函数,实现了关注点分离。无论是框架开发(Flask路由、Django权限)还是日常工具库,装饰器都能让代码更简洁、更Pythonic。掌握它,你的编程风格将迈上新台阶。