🧩 Python小练习系列:用装饰器记录函数执行时间
本节是 Python 小练习系列的一个子题,带你理解并动手写出一个能实用、可拓展的装饰器。
🎯 练习目标
- 理解 Python 装饰器(Decorator)的工作原理;
- 学会使用
@
装饰器语法糖; - 编写一个记录函数运行时间的装饰器;
- 掌握
functools.wraps
的正确使用方式; - 探索装饰器进阶应用场景。
🧠 一分钟理解什么是装饰器
"不改原函数的代码,就能给它增加功能?"
是的!装饰器是 Python 中的一种语法糖,它其实是一个返回函数的函数。装饰器常用于日志记录、权限验证、性能统计、缓存等场景。
举个例子:
python
def greet():
print("Hello!")
# 给 greet 函数加个装饰器:
def shout_decorator(func):
def wrapper():
print("Before call!")
func()
print("After call!")
return wrapper
greet = shout_decorator(greet)
greet()
输出:
r
Before call!
Hello!
After call!
换成语法糖的写法就是:
python
@shout_decorator
def greet():
print("Hello!")
💡 我们的练习:计时装饰器 @timeit
目标功能:
- 用
@timeit
装饰任意函数; - 执行前记录函数名;
- 执行后打印运行时间(精确到毫秒);
- 返回原函数的执行结果。
🔧 步骤 1:基础版装饰器
python
import time
def timeit(func):
def wrapper(*args, **kwargs):
print(f"⏱ 正在执行函数: {func.__name__}")
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"✅ 函数 {func.__name__} 执行完成,用时 {end - start:.4f} 秒")
return result
return wrapper
用法示例:
python
@timeit
def add(a, b):
time.sleep(0.5)
return a + b
print(add(10, 20))
输出:
csharp
⏱ 正在执行函数: add
✅ 函数 add 执行完成,用时 0.5003 秒
30
⚠️ 步骤 2:加入 functools.wraps
避免元信息丢失
python
import functools
def timeit(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f"⏱ 正在执行函数: {func.__name__}")
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"✅ 函数 {func.__name__} 执行完成,用时 {end - start:.4f} 秒")
return result
return wrapper
🧪 步骤 3:再测几个函数
python
@timeit
def multiply(a, b):
time.sleep(0.8)
return a * b
@timeit
def say_hello(name):
print(f"Hello, {name}!")
multiply(3, 4)
say_hello("Python")
🚀 进阶挑战(可选)
1. 参数化装饰器(带参数的装饰器)
python
def timeit(verbose=True):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
if verbose:
print(f"⏱ 正在执行函数: {func.__name__}")
start = time.time()
result = func(*args, **kwargs)
end = time.time()
if verbose:
print(f"✅ 函数 {func.__name__} 执行完成,用时 {end - start:.4f} 秒")
return result
return wrapper
return decorator
@timeit(verbose=False)
def fast_add(a, b):
return a + b
2. 装饰异步函数(使用 asyncio
)
python
import asyncio
def async_timeit(func):
@functools.wraps(func)
async def wrapper(*args, **kwargs):
start = time.time()
result = await func(*args, **kwargs)
end = time.time()
print(f"✅ 异步函数 {func.__name__} 执行完成,用时 {end - start:.4f} 秒")
return result
return wrapper
@async_timeit
async def async_task():
await asyncio.sleep(1)
asyncio.run(async_task())
📌 总结
技能点 | 说明 |
---|---|
@装饰器 |
增强函数功能的利器 |
*args, **kwargs |
保证适配各种函数参数 |
functools.wraps |
保持原函数元信息 |
参数化装饰器 | 更加灵活的扩展方式 |
异步函数装饰器 | 用于 async def 函数的异步装饰器 |
📚 推荐练习拓展
- 写一个权限检查装饰器(只允许 admin 用户执行函数);
- 写一个函数缓存装饰器(简单 LRU 缓存);
- 写一个失败自动重试的装饰器(异常自动重试 N 次);
- 把多个装饰器组合使用,看函数执行顺序。
如果这篇内容对你有帮助, 欢迎 点赞 👍 | 收藏 ⭐ | 关注 ❤️ 如果你有更好的想法,欢迎评论区留言分享~