写带参数的函数装饰器最纠结的是需要包好多层,最外层是接收参数的函数,它返回一个接收函数的的函数。但这样有个问题是,最终包装出来的装饰器必须加()调用一下,即使没有参数也需要这样做,因为调用这个最外层函数才能返回里面装饰器(就是接收函数的函数)。以前一篇为例,可以这样改进:
def opt_arguments(func): def meta_wrapper(*args, **kwargs): if len(args) == 1 and callable(args[0]): return func(args[0]) else: def meta_func(inner_func): return func(inner_func, *args, **kwargs) return meta_func return meta_wrapper @opt_arguments def annotation(func, **annotations): """ A decorator to collect all named args to function.__namedargs__, all anonymous args to function.__unnamedargs__, decorator's args to function.__annotations__. """ @functools.wraps(func) def func_wrapper(*args, **kwargs): argspec = inspect.getargspec(func) namedargs = inspect.getcallargs(func, *args, **kwargs) # def foo(a, b=0, *c, **d): pass # foo(1, b=2, c=3, d=4) will convert c=3 to namedargs. unnamedargs = namedargs.pop(argspec.varargs, ()) namedargs.update(namedargs.pop(argspec.keywords, {})) func_wrapper.__namedargs__ = namedargs func_wrapper.__unnamedargs__ = unnamedargs func_wrapper.__annotations__ = annotations func(*args, **kwargs) return func_wrapper
这样得到的annotation可以无参数使用: