You can abuse decorators, to add warnings for unusual types in debug mode:
import warnings
import functools
import numbers
debug = True
class TypeWarning(Warning):
pass
def warn_types(*pos_types):
def decorator(func):
if not debug:
return func
@functools.wraps(func)
def wrapper(*args):
for i, (x, t) in enumerate(zip(args, pos_types)):
if not isinstance(x, t):
warnings.warn("Expected %s got %s for argument %d of %s"
% (t.__name__, x.__class__.__name__,
i, func.__name__),
category=TypeWarning, stacklevel=2)
return func(*args)
return wrapper
return decorator
@warn_types(numbers.Number, numbers.Number)
def add(x, y):
return x + y
This produces warnings for the programmer without breaking the functionality, and they can be turned off by turning off the debug mode. They can be also removed by a simple search-replace after you've finished coding your project.
>>> print add(3, 4)
7
>>> print add("a", "b")
__main__:1: TypeWarning: Expected Number got str for argument 0 of add
__main__:1: TypeWarning: Expected Number got str for argument 1 of add
ab
Extending this for keyword arguments is non-trivial in the general case, unless you're on Python 3 and can take advantage of annotations, in case it can become very simple.