Bootstrap

Python--闭包和装饰器高级应用

闭包和装饰器是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
  • 每次调用fn1fn2时,都会打印带有相应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. 无限制缓存
  • 适用场景:当缓存空间足够大,或者缓存的数据量不是问题时。
  • 实现方式:简单地存储所有结果,不进行任何限制。
  • 示例
    
    
;