闭包
闭包是函数式编程的重要语法结构,它并不只是python中的概念,在所有函数式编程语言中的应用都很广泛。
什么是闭包
首先引用维基百科上闭包的解释:
在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量(该函数内部绑定的符号),也要包括自由变量(在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。捕捉时对于值的处理可以是值拷贝,也可以是名称引用,这通常由语言设计者决定,也可能由用户自行指定(如C++)。
简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行,这样的一个函数就称之为闭包。
在python中定义闭包
在python中定义闭包分为以下三步:
- 函数嵌套定义
- 内部函数引用了外部函数的变量
- 外部函数返回内部函数对象
当内部函数被返回时,闭包会对引用环境(外部函数的变量)进行保存,这样做的目的是即使外部函数的栈帧销毁了,内部函数依然可以使用这些变量。
闭包的示例代码
def line_conf(a, b):
def line(x):
return a * x + b
return line
# 只需要变换参数a,b,就可以获得不同的直线表达函数
line1 = line_conf(1, 1)
line2 = line_conf(4, 5)
print(line1(5), line2(5))
闭包的好处
通过给外部函数传递不同的参数可以产生不同的引用环境,不同的引用环境和相同的内部函数可以产生不同的闭包实例,这样就可以提高代码的可复用性。
装饰器
装饰器是通过闭包来实现的,它可以让其他函数在不需要修改代码的前提下增加额外的功能。
简单装饰器的示例代码
# 打印函数执行时间的装饰器
def show_time(func):
def wrapper():
start_time = time.time()
func()
end_time = time.time()
print('spend %s' % (end_time - start_time))
return wrapper
@show_time # foo=show_time(foo)
def foo():
print('foo')
time.sleep(3)
@show_time # bar=show_time(bar)
def bar():
print('bar')
time.sleep(2)
foo()
# foo
# spend 3.000171422958374
bar()
# bar
# spend 2.001114845275879
带参数装饰器的示例diamagnetic
# flag表示是否记录时间到日志中
def time_logger(flag=0):
def show_time(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print('spend %s' % (end_time - start_time))
if flag:
print('记录时间到日志')
return result
return wrapper
return show_time
@time_logger(1) # show_time=time_logger(1); add=show_time(add)
def add(*args, **kwargs):
time.sleep(1)
return sum(args)
@time_logger(0)
def fac(n):
return reduce(lambda x, y: x * y, range(1, n + 1))
print(add(2, 7, 5))
# spend 1.0000569820404053
# 记录时间到日志
# 14
print(fac(10))
# spend 0.0
# 3628800
参考文档
闭包 (计算机科学) —— 维基百科 https://zh.wikipedia.org/wiki/%E9%97%AD%E5%8C%85_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)