当前位置:   article > 正文

python之闭包_python 闭包

python 闭包

前言

闭包作为python高级特性中的一个,初学总觉其披着一层神秘的面纱,这里我们来一起揭开这层面纱吧。那什么是闭包呢?

闭包,又称闭包函数,和普通的嵌套函数类似,闭包中包含外部函数和内部函数,不同之处是闭包中外部函数返回的不是一个值,而是内部函数,即闭包对象;通常,该返回的函数会被赋值给一个变量,继而被调用执行。

为何要是用闭包

比如,已知三条直线上某一个点的横坐标x,求其纵坐标y。如果不使用闭包,实现如下:

  1. def line1(x):
  2.    return 2 * x + 1
  3. def line2(x):
  4.    return 3 * x + 2
  5. def line3(x):
  6.    return 5 * x + 3
  7. if __name__ == '__main__':
  8.    print(line1(2))
  9.    print(line2(2))
  10.    print(line3(2))

使用闭包,实现如下

  1. # 闭包
  2. def line_closure(a, b):
  3.    def line(x):
  4.        return a * x + b
  5.    return line
  6. if __name__ == '__main__':
  7.    line4 = line_closure(2, 1) # 返回闭包对象,赋值给line4
  8.    print(line4(2))            # 此处可调用闭包里的内部函数
  9.    line5 = line_closure(3, 2)
  10.    print(line5(2))
  11.    line6 = line_closure(5, 3)
  12.    print(line6(2))

5 8 13 5 8 13

以上两种方法结果一样,在只有三条直线的情况下,代码量区别不大,而当有几百条直线呢,我们是不是还要定义几百个函数呢,此时用闭包就会使代码变得简单美观,提高了代码的复用率。

闭包应用举例

给不同项目记录日志

  1. import logging
  2. def log_header_closure(project_name):
  3.    logging.basicConfig(level=logging.DEBUG, format='%(asctime)s [%(name)s] %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
  4.    logger = logging.getLogger(project_name)
  5.    def _logging(message, level):
  6.        if level == 'debug':
  7.            logger.debug(message)
  8.        elif level == 'warning':
  9.            logger.warning(message)
  10.        elif level == 'error':
  11.            logger.error(message)
  12.    return _logging
  13. if __name__ == '__main__':
  14.    project_1_logger = log_header_closure('project_1')
  15.    project_1_logger('this is a warning info', 'warning')
  16.    project_1_logger('this is a error info', 'error')
  17.    project_2_logger = log_header_closure('project_2')
  18.    project_2_logger('this is a warning info', 'warning')
  19.    project_2_logger('this is a error info', 'error')

2021-10-27 14:21:32 [project_1] WARNING this is a warning info

2021-10-27 14:21:32 [project_1] ERROR this is a error info

2021-10-27 14:21:32 [project_2] WARNING this is a warning info

2021-10-27 14:21:32 [project_2] ERROR this is a error info

闭包和装饰器

其实,装饰器就是闭包,只不过装饰器的外部函数参数是一个函数,内部函数对该函数进行加工修饰最后返回。

  1. def add(x, y):
  2.    return x + y
  3. # 装饰器,实际上就是一个闭包
  4. def wrap_outer(func):
  5.    def wrap_inner(x, y):
  6.        print(time.asctime())
  7.        print('run start')
  8.        result = func(x, y)
  9.        print('run finished')
  10.        print(time.asctime())
  11.        return result
  12.    return wrap_inner
  13. if __name__ == '__main__':
  14.    wrapper = wrap_outer(add)
  15.    print(wrapper(2, 3))

Wed Oct 27 11:59:19 2021

run start

run finished

Wed Oct 27 11:59:19 2021

5

接着,我们用python装饰器的“语法糖”来重新实现一下,让代码看起来更优雅些:

  1. from functools import wraps
  2. def wrap_outer(func):
  3.    @wraps(func)
  4.    def wrap_inner(*args, **kwargs):
  5.        print(time.asctime())
  6.        print('run start')
  7.        result = func(*args, **kwargs)
  8.        print('run finished')
  9.        print(time.asctime())
  10.        return result
  11.    return wrap_inner
  12. @wrap_outer
  13. def add(x, y):
  14.    return x + y
  15. if __name__ == '__main__':
  16.    print(add(2, 3))

Wed Oct 27 13:39:55 2021

run start

run finished

Wed Oct 27 13:39:55 2021

5

可以看出,执行结果跟上面闭包实现一模一样。

闭包和普通函数

闭包比普通函数多了一个'__closure__'属性,用来记录引用的外部函数的自由变量的地址。当闭包被调用时,会从该地址获取到该自由变量,并完成整体的函数调用。

如上面的日志例子:

  1. project_1_logger = log_header_closure('project_1')
  2. print('111', project_1_logger.__closure__)

(<cell at 0x03AF7370: Logger object at 0x0E56D1B0>,)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/855905
推荐阅读
相关标签
  

闽ICP备14008679号