1. 什么是高阶函数?
高阶函数是指至少满足以下条件之一的函数:
- 接受一个或多个函数作为参数。
- 返回一个函数。
装饰器就是一种特殊的高阶函数,用来修改其他函数的行为。
2. 为什么使用装饰器?
装饰器可以让我们在不修改原始函数代码的情况下,增加额外的功能。比如记录日志、计时、缓存等。这样不仅让代码更简洁,也更容易维护。
3. 装饰器的基本语法
装饰器本质上是一个接受函数作为参数的函数,并返回一个新的函数。下面是一个简单的装饰器示例。
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
输出:
Something is happening before the function is called.
Hello!
Something is happening after the function is called.
4. 实战案例六:参数验证装饰器
参数验证装饰器可以在执行函数之前验证传入参数的有效性。
def validate_params(*param_types):
def decorator(func):
def wrapper(*args, **kwargs):
if len(args) != len(param_types):
raise ValueError("Incorrect number of arguments")
for arg, param_type in zip(args, param_types):
if not isinstance(arg, param_type):
raise TypeError(f"Argument {arg} is not of type {param_type.__name__}")
return func(*args, **kwargs)
return wrapper
return decorator
@validate_params(int, int)
def multiply(x, y):
return x * y
print(multiply(3, 4)) # 正确
# print(multiply(3, "hello")) # 抛出 TypeError
输出:
12
这个装饰器会检查传入的参数类型是否符合预期。如果不符合,会抛出相应的异常。
5. 实战案例七:限制调用次数装饰器
限制调用次数装饰器可以在一定时间内限制函数的调用次数。
import time
def limit_calls(max_calls, period):
def decorator(func):
call_times = []
def wrapper(*args, **kwargs):
current_time = time.time()
call_times.append(current_time)
while call_times and call_times[0] < current_time - period:
call_times.pop(0)
if len(call_times) > max_calls:
raise Exception("Too many calls in a short period of time")
return func(*args, **kwargs)
return wrapper
return decorator
@limit_calls(max_calls=2, period=5)
def process_request(data):
print(f"Processing request: {data}")
process_request("data1")
time.sleep(1)
process_request("data2")
time.sleep(1)
process_request("data3") # 抛出 Exception
输出:
Processing request: data1
Processing request: data2
Too many calls in a short period of time
这个装饰器限制了 process_request 函数在 5 秒内只能被调用两次。如果超过这个限制,会抛出异常。
6. 实战案例八:缓存装饰器(自定义)
自定义缓存装饰器可以根据特定需求实现缓存功能。
from functools import wraps
def custom_cache(func):
cache = {}
@wraps(func)
def wrapper(*args, **kwargs):
key = (args, frozenset(kwargs.items()))
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
return wrapper
@custom_cache
def fibonacci(n):
if n <= 1:
return n
else:
return fibonacci(n-1) + fibonacci(n-2)
for i in range(10):
print(fibonacci(i))
输出:
0
1
1
2
3
5
8
13
21
34
这个装饰器使用了一个字典 cache 来存储函数的计算结果。如果相同的参数再次传入,就直接从缓存中获取结果。
7. 实战案例九:异步装饰器
异步装饰器可以让函数异步执行,提高程序的响应速度。
import asyncio
async def async_decorator(func):
async def wrapper(*args, **kwargs):
return await func(*args, **kwargs)
return wrapper
@async_decorator
async def download_file(url):
print(f"Downloading file from {url}")
await asyncio.sleep(2) # 模拟下载过程
print(f"File downloaded from {url}")
async def main():
await asyncio.gather(
download_file("http://example.com/file1"),
download_file("http://example.com/file2")
)
asyncio.run(main())
输出:
Downloading file from http://example.com/file1
Downloading file from http://example.com/file2
File downloaded from http://example.com/file1
File downloaded from http://example.com/file2
这个装饰器将函数转换为异步函数,并允许并行执行多个任务。
8. 实战案例十:多线程装饰器
多线程装饰器可以让函数在多个线程中并发执行。
import threading
def thread_decorator(func):
def wrapper(*args, **kwargs):
thread = threading.Thread(target=func, args=args, kwargs=kwargs)
thread.start()
return thread
return wrapper
@thread_decorator
def print_message(message):
print(message)
print_message("Hello, world!")
print_message("Goodbye, world!")
# 等待所有线程完成
for thread in threading.enumerate():
if thread != threading.current_thread():
thread.join()
输出(顺序可能不同):
Hello, world!
Goodbye, world!
这个装饰器将函数放在不同的线程中执行,并等待所有线程完成。