Python中的闭包
当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。
1 def make_printer(msg): 2 def printer(): 3 print(msg) # 夹带私货(外部变量) 4 return printer # 返回的是函数,带私货的函数 5 printer = make_printer('Foo!') 6 printer()
同一个的函数夹带了不同的私货,就实现了不同的功能。
1 def tag(tag_name): 2 def add_tag(content): 3 return "<{0}>{1}</{0}>".format(tag_name, content) 4 5 return add_tag 6 7 8 content = 'Hello' 9 10 add_tag = tag('a') 11 print(add_tag(content)) 12 # <a>Hello</a> 13 14 add_tag = tag('b') 15 print(add_tag(content)) 16 # <b>Hello</b>
Python中的装饰器Decorator,假如你需要写一个带参数的装饰器,那么一般都会生成闭包。
1 # how to define 2 def wrapper(func1): # 必须接受一个且仅一个函数作为参数 3 return func1 # 返回一个且仅一个callable对象,一般为函数 4 5 # how to use 6 def target_func(args):# 目标函数 7 pass 8 9 # 调用方式一,直接包裹 10 result = wrapper(target_func)(args) 11 12 # 调用方式二,使用@语法,等同于方式一 13 @wrapper 14 def target_func(args): 15 pass 16 17 result = target_func()
装饰器如果带参数呢?那么就需要在原来的装饰器上再包一层,用于接收这些参数。这些参数(私货)传递到内层的装饰器里后,闭包就形成了。所以说当装饰器需要自定义参数时,一般都会形成闭包。(类装饰器例外)
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 9 @html_tags('b') 10 def hello(name='Toby'): 11 return'Hello {}!'.format(name) 12 13 # 不用@的写法如下 14 # hello = html_tag('b')(hello) 15 # html_tag('b') 是一个闭包,它接受一个函数,并返回一个函数 16 17 print(hello()) # <b>Hello Toby!</b> 18 print(hello('world')) # <b>Hello world!</b>
其实闭包函数相对与普通函数会多出一个__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 7 >>> printer.__closure__ # 返回cell元组 8 (<cell at 0x03A10930: str object at 0x039DA218>, <cell at 0x03A10910: str object at 0x039DA488>) 9 10 >>> printer.__closure__[0].cell_contents # 第一个外部变量 11 'Foo' 12 >>> printer.__closure__[1].cell_contents # 第二个外部变量 13 'Bar'

浙公网安备 33010602011771号