Strict types decorator (works only with Python 3.5) I wrote a decorator which makes Python 3.5 raise exceptions if the arguments that are passed to a type-hinted function are of the wrong type.

from typing import get_type_hints

def strict_types(f):
    def type_checker(*args, **kwargs):
        hints = get_type_hints(f)

        all_args = kwargs.copy()
        all_args.update(dict(zip(f.__code__.co_varnames, args)))

        for key in all_args:
            if key in hints:
                if type(all_args[key]) != hints[key]:
                    raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))

        res = f(*args, **kwargs)

        if type(res) == hints['return']:
            return res
        else:
            raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))

    return type_checker


It's used like this:

@strict_types
def concatenate_with_spam(text: str) -&gt; str:
    return text + 'spam'


and if something of the wrong type is passed to the decorated function e.g. concatenate_with_spam(42) an exception is raised:

Exception: Type of text is &lt;class 'int'&gt; and not &lt;class 'str'&gt;


The part that I'm worried about is the part that checks the result. It calls the original function (to learn result of what type it returns), but returns a wrapped function type_checker that will be called one more time, so the runtime of function is (at least) multiplied by 2. Are there any other things I have missed? What can be improved here (except for not using this not-pythonic decorator and crucifying me for writing it)?
You should change this part a bit:

    for key in all_args:
        if key in hints:
            if type(all_args[key]) != hints[key]:
                raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))


Here, you are silently ignoring missing type hints, but if the user went as far as to use this decorator, you should raise an exception instead, like this:

    for key in all_args:
        try:
            if type(all_args[key]) != hints[key]:
                raise Exception('Type of {} is {} and not {}'.format(key, type(all_args[key]), hints[key]))
        except IndexError:
                raise TypeError('The formal parameter {} was not given a type'.format(key))


Specific Errors &amp; Exceptions

Exception is hilariously un-informative, use TypeError to convey more information.

Order of conditionals

    if type(res) == hints['return']:
        return res
    else:
        raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))


Here, the real logic is in the else, but I prefer seeing the main logic after the if, like this:

if type(res) != hints['return']:
    raise Exception('Type of result is {} and not {}'.format(type(res), hints['return']))
return res


Now it looks more like a simple perturbation of an almost linear function, than a full-blown logic statement.

Please do not abbreviate


res -&gt; result 
func -&gt; function


It takes 0.5 seconds more to type and a tenth of the time to read.