Writing a good decorator is no different then writing a good function. Which means, ideally, using docstrings and making sure the decorator is included in your testing framework.
You should definitely use either the decorator
library or, better, the functools.wraps()
decorator in the standard library (since 2.5).
Beyond that, it's best to keep your decorators narrowly focused and well designed. Don't use *args
or **kw
if your decorator expects specific arguments. And do fill in what arguments you expect, so instead of:
def keep_none(func):
def _exec(*args, **kw):
return None if args[0] is None else func(*args, **kw)
return _exec
... use ...
def keep_none(func):
"""Wraps a function which expects a value as the first argument, and
ensures the function won't get called with *None*. If it is, this
will return *None*.
>>> def f(x):
... return x + 5
>>> f(1)
6
>>> f(None) is None
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
>>> f = keep_none(f)
>>> f(1)
6
>>> f(None) is None
True"""
@wraps(func)
def _exec(value, *args, **kw):
return None if value is None else func(value, *args, **kw)
return _exec