闭包和装饰器是Python中两个强大的特性,它们可以显著提升代码的灵活性和性能。以下是一些闭包和装饰器的使用示例和解释。
1. 闭包
闭包允许函数记住并访问它们被创建时的环境。这使得闭包可以捕获并保存外部函数的变量,即使外部函数已经执行完毕。
示例:简单闭包
def outer(logo):
def inner(msg):
print(f"<{logo}>{msg}<{logo}>")
return inner
fn1 = outer("黑马程序员")
fn1("大家好") # 输出:<黑马程序员>大家好<黑马程序员>
fn1("大家好") # 输出:<黑马程序员>大家好<黑马程序员>
fn2 = outer("传智教育")
fn2("大家好") # 输出:<传智教育>大家好<传智教育>
解释:
outer
函数返回了一个inner
函数。inner
函数可以访问outer
函数的变量logo
。- 每次调用
fn1
或fn2
时,都会打印带有相应logo
的消息。
示例:使用nonlocal关键字修改外部函数的值
def outer(num1):
def inner(num2):
nonlocal num1
num1 += num2
print(num1)
return inner
fn = outer(10)
fn(10) # 输出:20
fn(10) # 输出:30
fn(10) # 输出:40
解释:
outer
函数返回了一个inner
函数。inner
函数使用nonlocal
关键字修改outer
函数的变量num1
。- 每次调用
fn
时,num1
的值都会增加num2
。
示例:使用闭包实现ATM小案例
def account_create(initial_amount=0):
def atm(num, deposit=True):
nonlocal initial_amount
if deposit:
initial_amount += num
print(f"存款:+{num}, 账户余额:{initial_amount}")
else:
initial_amount -= num
print(f"取款:-{num}, 账户余额:{initial_amount}")
return atm
atm = account_create()
atm(100) # 输出:存款:+100, 账户余额:100
atm(200) # 输出:存款:+200, 账户余额:300
atm(100, deposit=False) # 输出:取款:-100, 账户余额:200
解释:
account_create
函数返回了一个atm
函数。atm
函数可以访问并修改account_create
函数的变量initial_amount
。- 通过调用
atm
函数,可以进行存款和取款操作,并实时更新账户余额。
2. 装饰器
装饰器是一种设计模式,用于在不修改原始函数代码的情况下增加函数功能。
示例:计算函数执行时间的装饰器
import time
def time_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time() # 记录开始时间
result = func(*args, **kwargs) # 调用原始函数
end_time = time.time() # 记录结束时间
print(f"Function {func.__name__} executed in {end_time - start_time:.4f} seconds")
return result
return wrapper
@time_decorator
def example_function(n):
time.sleep(n) # 模拟耗时操作
return f"Function completed after {n} seconds"
result = example_function(2)
print(result)
输出:
Function example_function executed in 2.0023 seconds
Function completed after 2 seconds
解释:
time_decorator
是一个装饰器工厂函数,它接受一个函数func
作为参数。wrapper
是一个内部函数,它包装了原始函数func
的调用逻辑,并计算执行时间。
示例:带参数的装饰器
import time
def repeat_decorator(times):
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for _ in range(times):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
results.append(result)
print(f"Function {func.__name__} executed in {end_time - start_time:.4f} seconds")
return results
return wrapper
return decorator
@repeat_decorator(times=3)
def example_function(n):
time.sleep(n) # 模拟耗时操作
return f"Function completed after {n} seconds"
results = example_function(1)
for result in results:
print(result)
输出:
Function example_function executed in 1.0002 seconds
Function example_function executed in 1.0001 seconds
Function example_function executed in 1.0001 seconds
Function completed after 1 seconds
Function completed after 1 seconds
Function completed after 1 seconds
解释:
repeat_decorator
是一个带参数的装饰器工厂函数,它接受一个参数times
。decorator
是一个装饰器函数,它返回wrapper
函数,wrapper
函数包装了原始函数的调用逻辑,并重复执行times
次。
3. 缓存策略
选择合适的缓存策略是优化应用性能的关键。以下是一些常见的缓存策略及其特点:
1. LRU(最近最少使用)缓存
- 适用场景:当缓存空间有限,且希望缓存最近被访问的数据时。
- 实现方式:Python的
functools
模块提供了lru_cache
装饰器,可以自动实现LRU缓存。 - 示例:
from functools import lru_cache @lru_cache(maxsize=100) # 最多缓存100个结果 def compute_expensive_result(x): # 计算耗时的操作 return x * x
2. FIFO(先进先出)缓存
- 适用场景:当需要按访问顺序缓存数据时。
- 实现方式:可以使用队列实现FIFO缓存,但Python标准库中没有直接支持,需要自定义实现。
- 示例:
from collections import deque class FIFOCache: def __init__(self, capacity): self.cache = {} self.order = deque() self.capacity = capacity def get(self, key): if key in self.cache: self.order.remove(key) self.order.append(key) return self.cache[key] return None def put(self, key, value): if key in self.cache: self.order.remove(key) elif len(self.cache) >= self.capacity: oldest = self.order.popleft() del self.cache[oldest] self.cache[key] = value self.order.append(key) cache = FIFOCache(100) def cache_decorator(func): def wrapper(x): cached_result = cache.get(x) if cached_result is not None: return cached_result result = func(x) cache.put(x, result) return result return wrapper @cache_decorator def compute_expensive_result(x): return x * x
3. LFU(最少使用频率)缓存
- 适用场景:当希望缓存最常被访问的数据时。
- 实现方式:需要自定义实现,Python标准库中没有直接支持。
- 示例:
from collections import Counter class LFUCache: def __init__(self, capacity): self.cache = {} self.freq = Counter() self.capacity = capacity def get(self, key): if key not in self.cache: return -1 self.freq[key] += 1 return self.cache[key] def put(self, key, value): if key in self.cache: self.freq[key] += 1 else: if len(self.cache) >= self.capacity: least_freq_key = min(self.freq, key=self.freq.get) del self.cache[least_freq_key] del self.freq[least_freq_key] self.cache[key] = value self.freq[key] = 1 cache = LFUCache(100) def cache_decorator(func): def wrapper(x): cached_result = cache.get(x) if cached_result != -1: return cached_result result = func(x) cache.put(x, result) return result return wrapper @cache_decorator def compute_expensive_result(x): return x * x
4. 无限制缓存
- 适用场景:当缓存空间足够大,或者缓存的数据量不是问题时。
- 实现方式:简单地存储所有结果,不进行任何限制。
- 示例: