Python闭包与装饰器底层机制详解
本文深入解析Python中闭包的构成条件及其在装饰器中的应用。通过代码示例说明自由变量的生命周期管理,并重点讲解装饰器导致函数元信息丢失的问题及利用functools.wraps修复的方法,附带带时间统计功能的装饰器实现代码。
Python闭包的构成条件与原理
一、闭包
从结构上看,闭包是指在外部函数内部定义一个内部函数,且该内部函数引用了外部函数的变量,这类被引用的变量被称为自由变量。
本质上,闭包是将函数代码语句与其执行时的环境状态打包在一起形成的对象。
构建闭包需要满足以下三个条件:
必须存在一个内嵌函数。
该内嵌函数必须使用外部函数的变量。
外部函数的返回值必须是这个内嵌函数。
def closure():
value = []
def fun(tmp):
value.append(tmp)
return value
return fun
cc = closure()
cc(0) #[0] 等同于closure(fun(0))
cc(1) #[0,1]
cc(2) #[0,1,2]
在外部函数closure中,变量value与内部函数fun共同存在,且fun引用了自由变量value。当执行cc = closure()时,便生成了一个闭包对象fun。该闭包持有了变量value的引用,即使外部函数closure执行完毕,value依然存在于内存中,因为闭包对其进行了引用。
装饰器的实现与元信息处理
二、装饰器
装饰器本质上是闭包的一种具体应用形式,其传递和处理的目标是函数对象。
def add_time(fun):
def wrapper():
print('time: 12:00')
return fun()
return wrapper
def add_format(fun):
def wrapper():
print('\n')
return fun()
return wrapper
@add_format #等同于demo = add_format(add_time(demo))
@add_time #等同于 demo = add_time(demo)
def demo():
return 'hello world!'
需要注意的是,直接使用装饰器会导致原函数的元信息(如__name__等属性)丢失。
例如,原函数demo的__name__属性在装饰后会变为wrapper。为解决此问题,需引入functools库,在wrapper函数定义前添加@functools.wraps(fun)装饰器:
import functools
def add_time(fun):
@functools.wraps(fun)
def wrapper():
print('time: 12:00')
return fun()
return wrapper
def add_format(fun):
@functools.wraps(fun)
def wrapper():
print('\n')
return fun()
return wrapper
@add_format #等同于demo = add_format(add_time(demo))
@add_time #等同于 demo = add_time(demo)
def demo():
return 'hello world!'
以下示例展示如何编写一个为任意函数添加打印时间功能的装饰器:
def metric(fn):
start=time.time()
@functools.wraps(fn)
def wrapper(*args,**kw):
end=time.time()
print('%s executed in %s ms' % (fn.__name__,start-end))
return fn(*args,**kw)
return wrapper
以上内容涵盖了Python闭包与装饰器的核心原理及实践,希望能为读者的学习提供参考,欢迎继续支持本站获取更多技术内容。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













