闭包本质上是一个函数,其传入参数和返回值也都是函数,闭包函数的返回值函数是对传入函数进行增强后的结果
目的:在不侵入代码的情况下对函数进行增强;函数业务分类,分类关注点
缺点:需要对wrapper显式的调用(函数的显式增强:每次调用前都需要先调用wrapper)
装饰器约等于闭包,只是一种语法糖,本质上和闭包完全一致
@闭包函数的函数名
函数装饰器装饰在某个函数上,在第一次调用这个函数的时候,python的解释器会自动的增强被装饰的函数
故:python装饰器本质上是一个对函数闭包的语法糖,是函数闭包的简单写法
语法糖:没有增加新的功能,只是一种更方便的写法;可以完全的转化为原本菲语法糖的代码
说明:增强时机:第一次调用之前(没调用,则不增强)
增强次数:只增强一次
def last_wrapper(info: str): # 最外面一层的wrapper用于传参
def wrapper_1(fun):
def improved_fun1(*args, **kwargs):
result = fun(*args, **kwargs)
print(result)
return fun(*args, **kwargs)
return improved_fun1
return wrapper_1
@last_wrapper(info='info')
def fun(a: int, b: int) -> int:
return a+b
if __name__ == "__main__":
fun(1, 3)
# all_fun = last_wrapper(info='str')(fun=fun(1, 3))
# last_fun = last_wrapper(info='str')
# second_fun = last_fun(fun=fun)
# result = second_fun(1, 3)
# print(result)
mmdeploy中的装饰器——注册器机制
from typing import Dict, Type, Optional, Union, List, Callable
class Registry:
def __init__(self):
self._module_dict: Dict[str, Type] = dict()
def _register_module(self,
module: Type,
module_name: Optional[Union[str, List[str]]] = None,
force: bool = False) -> None:
if module_name is None:
module_name = module.__name__
if isinstance(module_name, str):
module_name = [module_name]
for name in module_name:
if not force and name in self._module_dict:
existed_module = self.module_dict[name]
raise KeyError(f'{name} is already registered in {self.name} '
f'at {existed_module.__module__}')
self._module_dict[name] = module
def register_module(
self,
name: Optional[Union[str, List[str]]] = None,
force: bool = False,
module: Optional[Type] = None) -> Union[type, Callable]:
# use it as a decorator: @x.register_module()
def _register(module):
self._register_module(module=module, module_name=name, force=force)
return module
return _register
DATASETS = Registry()
@DATASETS.register_module()
class ADE20KDataset:
def __init__(self) -> None:
pass
def get_label_ap(self) -> None:
pass
ADE20KDataset() # 无需调用,在装饰完成后,就会执行到self._module_dict[name] = module
- 生成一个Register的对象,对类ADE20KDataset使用register对象的register_module方法进行装饰
- 无需调用,在装饰完成后,就会在self._module_dict中维护一个从类名到类的一个映射
class A:
def __init__(self) -> None:
pass
def __call__(self, fun) :
print("the call fun")
fun()
print("the over")
@A()
def fun():
print("the fun")
结果打印为
the call fun
the fun
the over
class A:
def __init__(self) -> None:
pass
def __call__(self, fun) :
print("the call fun")
def improved_fun(*args, **kwargs):
fun(*args, **kwargs)
print("the over")
return improved_fun
@A()
def fun():
print("the fun")
结果为
the call fun
与函数装饰器不同的是,类方法对类的装饰,会执行改方法
def wrapper(fun):
def improved_fun(*args, **kwargs):
fun(*args, **kwargs)
return improved_fun
@wrapper
def fun(a: int) -> None:
print("the fun have been used")
没有结果输出
闭包
闭包内的函数,在外部函数执行结束后,复制了一份到内部函数自己的闭包里面
闭包形成的前提条件:
- 有嵌套的内部函数
- 外部函数里的变量被内部函数使用了
- 当外部函数执行结束后(greeting执行结束后,变量才复制到闭包属性里,所以值为second),那些变量的值仍然存在,被存在了内部函数的闭包属性.__closure__属性里面(是一个元组类型)
- 内部嵌套的函数和使用的变量的组合叫做闭包