Python: 收集所有命名参数

有时候把Python函数调用的命名参数都收集到一个dict中可以更方便地做参数检查,或者直接由参数创建attribute等。更简单的理解就是def foo(*args, **kwargs): pass可以接受所有的参数,其中kwargs就是命名参数字典,那么直接在函数外面套个foo却不能达到目的,一个比较简单的实现是这样的:

def annotation(**annotations):
	"""
	A decorator to collect all named args to function.__namedargs__,
	all anonymous args to function.__unnamedargs__,
	decorator's args to function.__annotations__.
	"""

	def func_decorator(func):
		@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

	return func_decorator

annotation的的用法仿照Python 3的Function Annotation,可以对参数做标记等,这里所有的标记都会存放在function.__annotations__中:

image

如果只要annotation,那么可以这样做避免额外调用开销:

def annotation(**anno):
	"""
	A decorator to update decorator's args to function.__annotations__.

	"""

	def func_decorator(func):
		"""
		Static check annotation.
		"""
		argspec = inspect.getargspec(func)
		callargs = set(argspec.args)
		callargs.add(argspec.varargs)
		callargs.add(argspec.keywords)
		invalid_keys = anno.viewkeys() - callargs
		if invalid_keys:
			raise TypeError('Invalid annotation keys = %s' % (invalid_keys))
		else:
			func.__annotations__ = anno
			return func

	return func_decorator
posted @ 2014-04-02 14:36  紫红的泪  阅读(2695)  评论(0编辑  收藏  举报