def require(arg_name, *allowed_types): def make_wrapper(f): if hasattr(f, "wrapped_args"): wrapped_args = getattr(f, "wrapped_args") else: code = f.func_code wrapped_args = list(code.co_varnames[:code.co_argcount]) try: arg_index = wrapped_args.index(arg_name) except ValueError: raise NameError, arg_name def wrapper(*args, **kwargs): if len(args) > arg_index: arg = args[arg_index] if not isinstance(arg, allowed_types): type_list = " or ".join(str(allowed_type) for allowed_type in allowed_types) raise TypeError, "Expected '%s' to be %s; was %s." % (arg_name, type_list, type(arg)) else: if arg_name in kwargs: arg = kwargs[arg_name] if not isinstance(arg, allowed_types): type_list = " or ".join(str(allowed_type) for allowed_type in allowed_types) raise TypeError, "Expected '%s' to be %s; was %s." % (arg_name, type_list, type(arg)) return f(*args, **kwargs) wrapper.wrapped_args = wrapped_args return wrapper return make_wrapper @require("x", int, float) @require("y", float) def foo(x, y): return x+y print foo(1, 2.5) # Prints 3.5. print foo(2.0, 2.5) # Prints 4.5. print foo("asdf", 2.5) # Raises TypeError exception. print foo(1, 2) # Raises TypeError exception.