在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。—— 维基百科
就是当内部的函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。闭包将捕捉内部函数执行所需的整个环境。看例子:
# coding=utf-8
def make_printer(msg=None):
def printer():
print(msg)
return printer
ob_printer=make_printer("Hello World!")
ob_printer()
print("闭包函数,夹带外部变量:")
print(ob_printer.__globals__)
print(ob_printer.__closure__)
print(ob_printer.__closure__[0].cell_contents)
def make_printer1():
def printer():
print()
return printer
ob_printer=make_printer1()
print("普通函数,不夹带外部变量:")
print(ob_printer.__globals__)
print(ob_printer.__closure__)
print(ob_printer.__closure__[0].cell_contents)
'''
Hello World!
闭包函数,夹带外部变量:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000049C2E8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:\\Users\\li\\workspace\\temp\\e\\ttt\\try7.py', '__cached__': None, 'make_printer': <function make_printer at 0x00000000003B4E18>, 'ob_printer': <function make_printer.<locals>.printer at 0x0000000001E8F268>}
(<cell at 0x0000000000120C48: str object at 0x0000000001E8CCB0>,)
Hello World!
普通函数,不夹带外部变量:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000000000049C2E8>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:\\Users\\li\\workspace\\temp\\e\\ttt\\try7.py', '__cached__': None, 'make_printer': <function make_printer at 0x00000000003B4E18>, 'ob_printer': <function make_printer1.<locals>.printer at 0x00000000023808C8>, 'make_printer1': <function make_printer1 at 0x0000000002380840>}
None
'''
如果需要在一系列函数调用中保持某个状态,使用闭包是一种非常高效的方式,例如,考虑下面运行了一个简单计数器的代码:
# coding=utf-8
def countdown(n):
def next():
nonlocal n
r=n
n-=1
return r
return next
def main_():
fo_countdown_next=countdown(10);
while True:
v=fo_countdown_next();
print(v);
if not v:
break
main_()
'''
10
9
8
7
6
5
4
3
2
1
0
'''