Higher-order Python Decorators

December 19, 2008

May you find them useful.

def simple_pre_decorator_maker(pre, *args, **kwargs):
	"""
	Returns a function that can be used as a decorator.
	Decorated function will call pre(*args, **kwargs) before its main contents.

	>>> def a():
	...     print "a"
	...
	>>> pre_a = simple_pre_decorator_maker(a)
	>>> @pre_a
	... def b():
	...     print "b"
	...
	>>> b()
	a
	b
	"""
	def wrapper(function):
		def new_function(*argz, **kwargz):
			pre(*args, **kwargs)
			return function(*argz, **kwargz)
		return new_function
	return wrapper

def simple_post_decorator_maker(post, *args, **kwargs):
	"""
	Returns a function that can be used as a decorator.
	Decorated function will call post(*args, **kwargs) after its main contents.

	>>> def a():
	...     print "a"
	...
	>>> post_a = simple_post_decorator_maker(a)
	>>> @post_a
	... def b():
	...     print "b"
	...
	>>> b()
	b
	a
	"""
	def wrapper(function):
		def new_function(*argz, **kwargz):
			result = function(*argz, **kwargz)
			post(*args, **kwargs)
			return result
		return new_function
	return wrapper

def overriding_pre_decorator_maker(pre):
	"""
	Returns a function that can be used as a decorator.
	Decorated function will call pre(*args, **kwargs) before its main contents,
	where args and kwargs are the arguments to the decorated function.
	If pre() returns a value, it will be used as the decorated return value.
	If pre() returns None, None will be used as the decorated return value.

	>>> def none_returner():
	...     return None
	...
	>>> def true_returner():
	...     return True
	...
	>>> do_nothing_decorator = overriding_pre_decorator_maker(none_returner)
	>>> @do_nothing_decorator
	... def a_returner():
	...     return "A"
	...
	>>> a_returner()
	'A'
	>>> force_true_decorator = overriding_pre_decorator_maker(true_returner)
	>>> @force_true_decorator
	... def a_returner():
	...     return "A"
	...
	>>> a_returner()
	True
	"""
	def wrapper(function):
		def new_function(*args, **kwargs):
			return pre(*args, **kwargs) or function(*args, **kwargs)
		return new_function
	return wrapper

def overriding_post_decorator_maker(post):
	"""
	Returns a function that can be used as a decorator.
	Decorated function will call return post(result) after their main contents,
	where result is the return value of the original function.

	>>> def increment(x):
	...     return x + 1
	...
	>>> successor = overriding_post_decorator_maker(increment)
	>>> @successor
	... def two():
	...     return 1
	...
	>>> two()
	2

	"""
	def wrapper(function):
		def new_function(*args, **kwargs):
			return post(function(*args, **kwargs))
		return new_function
	return wrapper

Advertisements
%d bloggers like this: