当前位置:   article > 正文

Python中的闭包_python 闭包

python 闭包

一、定义

如果一个函数定义在另一个函数内部,而内部函数使用了外部函数的变量,则称这个内部函数为闭包。也就是说,当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包

  1. def make_printer(msg):
  2. def printer():
  3. print(msg)
  4. return printer
  5. if __name__ == '__main__':
  6. printer1 = make_printer('fool')
  7. printer2 = make_printer('stupid')
  8. printer1()
  9. printer2()
'
运行

  

二、特点

1、内部函数引用了外部函数的变量,这些变量不会在函数调用结束后被销毁。

2、外部函数返回内部函数的引用,这些外部函数的局部变量就可以被内部函数访问和修改。

三、意义

闭包存在的意义就是它夹带了外部变量(私货),如果它不夹带私货,它和普通的函数就没有任何区别。同一个的函数夹带了不同的私货,就实现了不同的功能。

  1. def tag(tag_name):
  2. def add_tag(content):
  3. print('<{0}>{1}</{0}>'.format(tag_name, content))
  4. return add_tag
  5. content = 'hello'
  6. if __name__ == '__main__':
  7. add_tag = tag('a')
  8. add_tag(content)
  9. add_tag = tag('b')
  10. add_tag(content)
'
运行

 四、闭包应用场景

1、Python中的装饰器Decorator

假如你需要写一个带参数的装饰器,那么一般都会生成闭包。

装饰器:在不改变原有函数代码的情况下,增加额外的功能,比如日志记录性能分析等。装饰器的详解参考 Python中的装饰器

初级装饰器通用写法:

  1. '''
  2. def wrapper(func1):
  3. return func2
  4. # 调用方式一,直接包裹
  5. def target_func(args):
  6. pass
  7. result = wrapper(target_func)(args)
  8. # 调用方式二,使用@语法,等同于方式一
  9. @wrapper
  10. def target_func(args):
  11. pass
  12. result = target_func()
  13. '''
'
运行

装饰器的一个例子: 

  1. def html_tags(tag_name):
  2. def wrapper_(func):
  3. def wrapper(*args, **kwargs):
  4. content = func(*args, **kwargs)
  5. return "<{tag}>{content}</{tag}>".format(tag=tag_name, content=content)
  6. return wrapper
  7. return wrapper_
  8. @html_tags('b')
  9. def hello(name='Toby'):
  10. return 'Hello {}!'.format(name)
  11. # 不用@的写法如下
  12. # hello = html_tag('b')(hello)
  13. # html_tag('b') 是一个闭包,它接受一个函数,并返回一个函数
  14. if __name__ == '__main__':
  15. # print(hello()) # <b>Hello Toby!</b>
  16. print(hello('world')) # <b>Hello world!</b>
'
运行

 

2、缓存函数

使用memorize装饰器将计算结果缓存起来,以避免重复计算。 

  1. def memoize(func):
  2. cache = {}
  3. def wrapper(*args):
  4. if args in cache:
  5. return cache[args]
  6. result = func(*args)
  7. return wrapper
  8. def fibonacci(n):
  9. if n in (0, 1):
  10. return n
  11. return fibonacci(n - 1) + fibonacci(n - 2)
  12. if __name__ == '__main__':
  13. print(fibonacci(10))
'
运行

在这个例子中,我们定义了一个memoize装饰器函数,它可以缓存被装饰函数的结果。 

3、延迟执行

闭包可以用来实现延迟执行,也就是在函数被调用时才进行计算。这可以提高程序的性能,特别是在计算复杂的表达式时。 

  1. def delayed_sum(a, b):
  2. def sum():
  3. return a + b
  4. return sum
  5. if __name__ == '__main__':
  6. result = delayed_sum(1, 2)
  7. print(result()) # 3
'
运行

当我们调用delayed_sum函数时,它不会计算ab的和,而是返回一个sum函数。当我们调用sum函数时,它才会计算ab的和并返回结果。 

4、实现类似于私有变量的功能

  1. def counter():
  2. count = 0
  3. def inner():
  4. nonlocal count
  5. count += 1
  6. return count
  7. return inner
  8. if __name__ == '__main__':
  9. c1 = counter()
  10. c2 = counter()
  11. print(c1())
  12. print(c1())
  13. print(c2())
  14. print(c2())
'
运行

  

由于 Python 中没有直接定义私有变量的语法,我们使用了一个内部函数(inner)来访问外部函数(counter)中的变量(count)。 

五、闭包的原理

其实闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象一一保存了这个闭包中所有的外部变量。

  1. def make_printer(msg1, msg2):
  2. def printer():
  3. print(msg1, msg2)
  4. return printer
  5. printer = make_printer('Foo', 'Bar') # 形成闭包
  6. print(printer.__closure__) # 返回cell元组
  7. print(printer.__closure__[0].cell_contents) # 第一个外部变量
  8. print(printer.__closure__[1].cell_contents) # 第二个外部变量
'
运行

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

闽ICP备14008679号