Python:闭包和装饰器

闭包

闭包是函数式编程的重要语法结构,它并不只是python中的概念,在所有函数式编程语言中的应用都很广泛。

什么是闭包

首先引用维基百科上闭包的解释:

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量(该函数内部绑定的符号),也要包括自由变量(在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。捕捉时对于值的处理可以是值拷贝,也可以是名称引用,这通常由语言设计者决定,也可能由用户自行指定(如C++)。

简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行,这样的一个函数就称之为闭包。

在python中定义闭包

在python中定义闭包分为以下三步:

  1. 函数嵌套定义
  2. 内部函数引用了外部函数的变量
  3. 外部函数返回内部函数对象

当内部函数被返回时,闭包会对引用环境(外部函数的变量)进行保存,这样做的目的是即使外部函数的栈帧销毁了,内部函数依然可以使用这些变量。

闭包的示例代码

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)

猜你喜欢

转载自blog.csdn.net/xingjingb/article/details/81356801