1 装饰器基础知识
- 装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或可调用函数
@deco
等价于target = deco(target)
def deco(func):
def inner():
print('running inner()')
func()
return inner
@deco
def target():
print('running target()')
2 对带参数的函数使用装饰器
@deco
等价于target = deco(target)(*args)
=>inner(*args)
def deco(func):
def inner(*args):
print('running inner {}'.format(args))
func(*args)
return inner
@deco
def target(*args):
print('running target {}'.format(args))
3 装饰器携带参数
@outer
等价于target = outer("deco")(target)(*args)
=>deco(target)(*args)
=>inner(*args)
def outer(*ar):
def deco(func):
def inner(*args):
print("outer 参数是{}".format(ar))
print('running inner {}'.format(args))
func(*args)
return inner
return deco
@outer("deco")
def target(*args):
print('running target {}'.format(args))
4 装饰器应用
在Detectron2 中,对一个类或函数进行注册时,就应用了python装饰器的特性
class Registry(object):
def __init__(self, name):
"""
Args:
name (str): the name of this registry
"""
self._name = name
self._obj_map = {}
def _do_register(self, name, obj):
assert (
name not in self._obj_map
), "An object named '{}' was already registered in '{}' registry!".format(name, self._name)
self._obj_map[name] = obj
def register(self, obj=None):
"""
Register the given object under the the name `obj.__name__`.
Can be used as either a decorator or not. See docstring of this class for usage.
"""
if obj is None:
# used as a decorator
def deco(func_or_class):
name = func_or_class.__name__
self._do_register(name, func_or_class)
return func_or_class
return deco
# used as a function call
name = obj.__name__
self._do_register(name, obj)
def get(self, name):
ret = self._obj_map.get(name)
if ret is None:
raise KeyError("No object named '{}' found in '{}' registry!".format(name, self._name))
return ret
registry_machine = Registry('registry_machine')
@registry_machine.register()
def print_hello_world(word):
print('hello {}'.format(word))
@registry_machine.register()
def print_hi_world(word):
print('hi {}'.format(word))
if __name__ == '__main__':
cfg1 = 'print_hello_world'
registry_machine.get(cfg1)('world')
cfg2 = 'print_hi_world'
registry_machine.get(cfg2)('world')