Python中的闭包机制简介
Introduction
闭包(Closure )是 Python 中一个非常重要且常用的概念,它是函数式编程的核心特性之一。闭包是一个函数,它“记住”了它被创建时的环境,即使在其环境之外被调用,这些变量仍然可用。换句话说:一个函数返回了另一个函数,这个返回的函数引用了其外部函数的变量 ,这个内部函数就是一个闭包。
闭包的三个必要条件 :
嵌套函数 :函数内部定义了另一个函数;
内部函数引用了外部函数的变量(自由变量) ;
外部函数返回了内部函数 。
例如:
1 2 3 4 5 6 7 def outer (x ): def inner (y ): return x + y return inner f = outer(10 ) print (f(5 ))
每当函数内部引用了外部作用域的变量时,Python 会将这些变量“捕获”并保存在闭包中。
我们可以用函数的 closure 属性查看闭包中存储的内容:
1 print (f.__closure__[0 ].cell_contents)
Usage
数据隐藏(类似于私有变量)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 def make_counter (): count = 0 def counter (): nonlocal count count += 1 return count return counter c1 = make_counter() print (c1()) print (c1()) c2 = make_counter() print (c2())
如果你在一个函数内定义了另一个函数(形成闭包),而你想在内部函数中修改外部函数的变量 ,就需要用 nonlocal 来声明这个变量。nonlocal 是 Python 3 中引入的一个关键字,用于在嵌套函数中声明一个变量不是局部变量 ,而是来自于最近一层的外部(非全局)作用域 。
回调函数
1 2 3 4 5 6 7 def make_multiplier (factor ): def multiply (n ): return n * factor return multiply double = make_multiplier(2 ) print (double(10 ))
函数工厂
1 2 3 4 5 6 7 8 9 10 def power_factory (exp ): def power (x ): return x ** exp return power square = power_factory(2 ) cube = power_factory(3 ) print (square(5 )) print (cube(2 ))
装饰器的本质也是闭包!
1 2 3 4 5 6 7 8 9 10 11 12 13 def my_decorator (func ): def wrapper (*args, **kwargs ): print ("Before function call" ) result = func(*args, **kwargs) print ("After function call" ) return result return wrapper @my_decorator def greet (name ): print (f"Hello, {name} " ) greet("Alice" )
进一步的,我们可以使用装饰器来为函数计时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import timedef timer (func ): def wrapper (*args, **kwargs ): start = time.time() result = func(*args, **kwargs) end = time.time() print (f"函数 `{func.__name__} ` 运行耗时:{end - start:.6 f} 秒" ) return result return wrapper @timer def slow_function (): time.sleep(2 ) print ("任务完成" ) slow_function()
再进一步的,我们对装饰器进行增强,使其能够同时实现:
✅ 打印日志(函数名称和参数)
⏱ 计时执行时间
⚠️ 自动捕获异常并打印错误信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import timeimport functoolsimport tracebackdef log_timer_exception (func ): @functools.wraps(func ) def wrapper (*args, **kwargs ): print (f"[LOG] 正在调用函数 `{func.__name__} `" ) print (f"[LOG] 参数: args={args} , kwargs={kwargs} " ) start_time = time.time() try : result = func(*args, **kwargs) except Exception as e: print (f"[ERROR] 函数 `{func.__name__} ` 执行出错: {e} " ) traceback.print_exc() result = None else : print (f"[LOG] 函数 `{func.__name__} ` 返回结果: {result} " ) finally : end_time = time.time() print (f"[TIME] 函数 `{func.__name__} ` 执行耗时: {end_time - start_time:.6 f} 秒\n" ) return result return wrapper
调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @log_timer_exception def divide (a, b ): return a / b @log_timer_exception def sleep_task (seconds ): time.sleep(seconds) return f"休眠 {seconds} 秒完成" divide(10 , 2 ) divide(10 , 0 ) sleep_task(1 )
输出:
1 2 3 4 5 6 7 8 9 10 11 12 [LOG] 正在调用函数 `divide` [LOG] 参数: args=(10, 2), kwargs={} [LOG] 函数 `divide` 返回结果: 5.0 [TIME] 函数 `divide` 执行耗时: 0.000002 秒 [LOG] 正在调用函数 `divide` [LOG] 参数: args=(10, 0), kwargs={} [ERROR] 函数 `divide` 执行出错: division by zero Traceback (most recent call last): ... ZeroDivisionError: division by zero [TIME] 函数 `divide` 执行耗时: 0.000004 秒
闭包+lamba表达式
lambda 常用于创建简单闭包:
1 2 3 4 5 def make_adder (x ): return lambda y: x + y add5 = make_adder(5 ) print (add5(3 ))