Python simple type checking decorator I'd like to know your opinions on this minimal type-checking decorator  (with @ annotations) to make type checking of a method while debugging like :

def typecheck(*tuples, **kwtuples):
    def decorator(func):
        def function_wrapper(*args, **kwargs):

            #print('tuples : ' , tuples)
            #print('kwtuples : ' , kwtuples)            
            #print('args : ' , args)            
            #print('kwargs : ' , kwargs)

            for index, tup in enumerate(tuples):
                arg = args[index]
                if not isinstance(arg, tup):
                    raise ValueError('in ' + str(func.__name__) + ' : wrong argument on position ,' + str(index) + ' :'  + str(arg) + ' must be of type :' + str(tup) + 'but is' + str(type(arg)) )

            for key, tup in kwtuples.items():
                arg = kwargs[key]
                if not isinstance(args[index], tup):
                    raise ValueError('in ' + str(func.__name__) + ' : wrong argument ' + str(key) + ' :'  + str(arg) + ' must be of type :' + str(tup) + 'but is' + str(type(arg)) )




        #print("arguments: ", *args, **kwargs)
            func(*args, **kwargs)
        return function_wrapper
    return decorator


@typecheck(str,(str, float))    
def foo2(x,y):
    print("Hi, foo has been called with ",str(x) ,y)

foo2('2',3.4)



The benefit of it is :


Custom and detailed description about the wrong argument
Later, you can extend this for custom validation like some item is in some range or structural inspection of an argument.
Easy to write, apply and delete after testing (so it won't consume cpu time)
To amplify @200_success’s comment:

Python 3.5 introduces type hints.  Eg)

&gt;&gt;&gt; def foo2(x:str, y:float) -&gt; None:
...    print(f"Hi, foo has been called with {x} {y}")
... 
&gt;&gt;&gt; foo2("2", 3.4)
Hi, foo has been called with 2 3.4
&gt;&gt;&gt;


These type hints (the x:str, and y:float) are not used by the standard Python interpreter, but they are recorded during the parsing of the code, so they are available to the program.

&gt;&gt;&gt; foo2.__annotations__
{'return': None, 'x': &lt;class 'str'&gt;, 'y': &lt;class 'float'&gt;}
&gt;&gt;&gt; 


Directly accessing the foo2.__annotations__ is not that interesting, but accessing func.__annotations__ in the @typecheck decorator means you don’t have to provide the argument types to the decorator; the decorator can inspect the argument types directly.  Thus you could decorate the function with simply @typecheck, instead of @typecheck(str, float).

For a variant str or float type argument, you could use the typing module to define your own STR_OR_FLOAT = TypeVar("STR_OR_FLOAT", str, float) type (or a better name if you have one), which you could decorate the argument with.

As a bonus, using type hints to provide argument type checking information — even for your do-it-yourself via a function decorator type check system — also gives you the following benefits:


IDE type hints, as you are writing code
Can be understood by standard documentation generators
Only consumes CPU time during parsing of the code; does not affect execution speed