乐闻世界logo
搜索文章和话题

Python 中的闭包是什么?如何使用?

2月21日 17:10

Python 中的闭包详解

闭包的基本概念

闭包是 Python 中一个重要的概念,它是指一个函数对象,即使在其定义作用域之外执行时,仍然能够访问其定义作用域中的变量。

闭包的基本结构

python
def outer_function(x): """外部函数""" def inner_function(y): """内部函数""" return x + y return inner_function # 创建闭包 closure = outer_function(10) # 调用闭包 print(closure(5)) # 15 print(closure(20)) # 30

闭包的三个条件

  1. 必须有一个嵌套函数(内部函数)
  2. 内部函数必须引用外部函数中的变量
  3. 外部函数必须返回这个内部函数
python
def make_multiplier(factor): """创建乘法闭包""" def multiply(number): return number * factor return multiply # 创建不同的乘法器 double = make_multiplier(2) triple = make_multiplier(3) print(double(5)) # 10 print(triple(5)) # 15

闭包的工作原理

变量的作用域

python
def outer(): x = 10 def inner(): # 内部函数可以访问外部函数的变量 print(f"内部函数访问 x: {x}") return x return inner closure = outer() print(closure()) # 内部函数访问 x: 10, 10

变量的生命周期

python
def counter(): """计数器闭包""" count = 0 def increment(): nonlocal count count += 1 return count return increment # 创建计数器 my_counter = counter() print(my_counter()) # 1 print(my_counter()) # 2 print(my_counter()) # 3 # 创建另一个计数器 another_counter = counter() print(another_counter()) # 1

closure 属性

python
def outer(x): def inner(y): return x + y return inner closure = outer(10) # 查看闭包的变量 print(closure.__closure__) # (<cell at 0x...: int object at 0x...>,) print(closure.__closure__[0].cell_contents) # 10

闭包的实际应用

1. 数据隐藏和封装

python
def make_account(initial_balance): """创建银行账户""" balance = initial_balance def deposit(amount): nonlocal balance balance += amount return balance def withdraw(amount): nonlocal balance if amount <= balance: balance -= amount return balance else: raise ValueError("余额不足") def get_balance(): return balance # 返回多个函数 return { 'deposit': deposit, 'withdraw': withdraw, 'get_balance': get_balance } # 创建账户 account = make_account(100) # 使用账户 print(account['deposit'](50)) # 150 print(account['withdraw'](30)) # 120 print(account['get_balance']()) # 120 # balance 变量被隐藏,无法直接访问 # print(balance) # NameError: name 'balance' is not defined

2. 函数工厂

python
def make_power_function(power): """创建幂函数""" def power_function(base): return base ** power return power_function # 创建不同的幂函数 square = make_power_function(2) cube = make_power_function(3) fourth_power = make_power_function(4) print(square(3)) # 9 print(cube(3)) # 27 print(fourth_power(3)) # 81

3. 延迟计算

python
def lazy_sum(*args): """延迟求和""" def sum(): total = 0 for num in args: total += num return total return sum # 创建延迟求和函数 f = lazy_sum(1, 2, 3, 4, 5) # 调用时才计算 print(f()) # 15

4. 缓存和记忆化

python
def memoize(func): """记忆化装饰器""" cache = {} def memoized(*args): if args not in cache: cache[args] = func(*args) return cache[args] return memoized @memoize def fibonacci(n): """斐波那契数列""" if n < 2: return n return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(10)) # 55 print(fibonacci(20)) # 6765

5. 回调函数

python
def make_callback(callback): """创建回调函数""" def execute(*args, **kwargs): print("执行回调前...") result = callback(*args, **kwargs) print("执行回调后...") return result return execute def my_function(x, y): return x + y # 创建带回调的函数 callback_function = make_callback(my_function) print(callback_function(3, 5)) # 执行回调前..., 8, 执行回调后...

6. 状态保持

python
def make_state_machine(): """创建状态机""" state = 'idle' def transition(action): nonlocal state print(f"当前状态: {state}, 动作: {action}") if state == 'idle': if action == 'start': state = 'running' elif state == 'running': if action == 'pause': state = 'paused' elif action == 'stop': state = 'idle' elif state == 'paused': if action == 'resume': state = 'running' elif action == 'stop': state = 'idle' print(f"新状态: {state}") return state return transition # 创建状态机 state_machine = make_state_machine() state_machine('start') # idle -> running state_machine('pause') # running -> paused state_machine('resume') # paused -> running state_machine('stop') # running -> idle

闭包与装饰器

闭包实现装饰器

python
def my_decorator(func): """简单的装饰器""" def wrapper(): print("装饰器:函数调用前") result = func() print("装饰器:函数调用后") return result return wrapper @my_decorator def say_hello(): print("Hello!") say_hello() # 输出: # 装饰器:函数调用前 # Hello! # 装饰器:函数调用后

带参数的装饰器

python
def repeat(times): """重复执行装饰器""" def decorator(func): def wrapper(*args, **kwargs): results = [] for _ in range(times): result = func(*args, **kwargs) results.append(result) return results return wrapper return decorator @repeat(3) def greet(name): return f"Hello, {name}!" print(greet("Alice")) # 输出: ['Hello, Alice!', 'Hello, Alice!', 'Hello, Alice!']

闭包的注意事项

1. 循环变量的陷阱

python
# 错误的做法 def create_multipliers(): return [lambda x: x * i for i in range(5)] multipliers = create_multipliers() print([m(2) for m in multipliers]) # [8, 8, 8, 8, 8] - 错误! # 正确的做法 - 使用默认参数 def create_multipliers_correct(): return [lambda x, i=i: x * i for i in range(5)] multipliers_correct = create_multipliers_correct() print([m(2) for m in multipliers_correct]) # [0, 2, 4, 6, 8] - 正确

2. 修改外部变量

python
def outer(): count = 0 def increment(): nonlocal count # 必须使用 nonlocal 关键字 count += 1 return count return increment counter = outer() print(counter()) # 1 print(counter()) # 2

3. 内存泄漏风险

python
def large_closure(): """创建大闭包""" large_data = list(range(1000000)) def process(): return sum(large_data[:100]) return process # 闭包会保持对 large_data 的引用 # 即使只使用其中的一小部分 closure = large_closure() # 如果不再需要闭包,应该删除引用 del closure

闭包 vs 类

闭包实现

python
def make_counter(): """使用闭包实现计数器""" count = 0 def increment(): nonlocal count count += 1 return count def get_count(): return count return { 'increment': increment, 'get_count': get_count } counter = make_counter() print(counter['increment']()) # 1 print(counter['increment']()) # 2 print(counter['get_count']()) # 2

类实现

python
class Counter: """使用类实现计数器""" def __init__(self): self.count = 0 def increment(self): self.count += 1 return self.count def get_count(self): return self.count counter = Counter() print(counter.increment()) # 1 print(counter.increment()) # 2 print(counter.get_count()) # 2

何时使用闭包 vs 类

python
# 使用闭包的场景: # 1. 简单的状态保持 def make_accumulator(): total = 0 def add(value): nonlocal total total += value return total return add # 2. 函数工厂 def make_power(power): def power_function(base): return base ** power return power_function # 使用类的场景: # 1. 复杂的状态管理 class BankAccount: def __init__(self, initial_balance): self.balance = initial_balance self.transactions = [] def deposit(self, amount): self.balance += amount self.transactions.append(('deposit', amount)) def withdraw(self, amount): if amount <= self.balance: self.balance -= amount self.transactions.append(('withdraw', amount)) def get_balance(self): return self.balance def get_transactions(self): return self.transactions # 2. 需要多个方法和属性 class Calculator: def __init__(self): self.history = [] def add(self, a, b): result = a + b self.history.append(f"{a} + {b} = {result}") return result def subtract(self, a, b): result = a - b self.history.append(f"{a} - {b} = {result}") return result def get_history(self): return self.history

闭包的高级应用

1. 部分函数应用

python
def partial(func, *args, **kwargs): """部分函数应用""" def wrapper(*more_args, **more_kwargs): all_args = args + more_args all_kwargs = {**kwargs, **more_kwargs} return func(*all_args, **all_kwargs) return wrapper def power(base, exponent): return base ** exponent square = partial(power, exponent=2) cube = partial(power, exponent=3) print(square(5)) # 25 print(cube(5)) # 125

2. 函数组合

python
def compose(*functions): """函数组合""" def wrapper(arg): result = arg for func in reversed(functions): result = func(result) return result return wrapper def add_one(x): return x + 1 def multiply_two(x): return x * 2 def square(x): return x ** 2 # 组合函数 combined = compose(square, multiply_two, add_one) print(combined(3)) # ((3 + 1) * 2) ** 2 = 64

3. 验证器

python
def make_validator(validator_func, error_message): """创建验证器""" def validate(value): if not validator_func(value): raise ValueError(error_message) return value return validate # 创建验证器 is_positive = make_validator( lambda x: x > 0, "值必须为正数" ) is_email = make_validator( lambda x: '@' in x and '.' in x, "无效的邮箱地址" ) # 使用验证器 print(is_positive(10)) # 10 # is_positive(-5) # ValueError: 值必须为正数 print(is_email("user@example.com")) # user@example.com # is_email("invalid") # ValueError: 无效的邮箱地址

4. 限流器

python
import time def rate_limiter(max_calls, time_window): """创建限流器""" calls = [] def limiter(func): def wrapper(*args, **kwargs): current_time = time.time() # 移除超出时间窗口的调用记录 calls[:] = [call_time for call_time in calls if current_time - call_time < time_window] # 检查是否超过限制 if len(calls) >= max_calls: raise Exception(f"超过限流限制:{max_calls} 次/{time_window} 秒") # 记录调用 calls.append(current_time) # 执行函数 return func(*args, **kwargs) return wrapper return limiter @rate_limiter(max_calls=3, time_window=1) def api_call(): print("API 调用成功") return "success" # 测试限流 api_call() # 成功 api_call() # 成功 api_call() # 成功 # api_call() # Exception: 超过限流限制:3 次/1 秒

总结

Python 闭包的核心概念:

  1. 基本定义:闭包是一个函数对象,能够访问其定义作用域中的变量
  2. 三个条件:嵌套函数、引用外部变量、返回内部函数
  3. 工作原理:通过 __closure__ 属性保持对外部变量的引用

闭包的实际应用:

  • 数据隐藏和封装
  • 函数工厂
  • 延迟计算
  • 缓存和记忆化
  • 回调函数
  • 状态保持

闭包的注意事项:

  • 循环变量的陷阱
  • 使用 nonlocal 修改外部变量
  • 注意内存泄漏风险

闭包 vs 类:

  • 闭包:适合简单的状态保持和函数工厂
  • 类:适合复杂的状态管理和多个方法

闭包的高级应用:

  • 部分函数应用
  • 函数组合
  • 验证器
  • 限流器

闭包是 Python 中一个强大而优雅的特性,它允许函数保持状态,实现数据隐藏,并创建更加灵活和可重用的代码。掌握闭包对于编写高质量的 Python 代码非常重要。

标签:Python