Assert types of the function arguments and return value.
    :param return_type: expected type of the return value
    :param arg_types: expected types of the arguments

    :example:
    @types(float, x=int, y=float, z=ListOf(int))
    def f(x, y, z):
        return x * y + sum(z)

def types(*return_type, **arg_types):
    """
    Assert types of the function arguments and return value.
    :param return_type: expected type of the return value
    :param arg_types: expected types of the arguments

    :example:
    @types(float, x=int, y=float, z=ListOf(int))
    def f(x, y, z):
        return x * y + sum(z)
    """
    assert len(return_type) <= 1, 'You can specify at most one return type.'

    arg_msg = '%s must be %s, not %s.'
    return_msg = 'must return %s, not %s.'

    def f(func):
        import functools

        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # convert args to call args
            call_args = getcallargs(func, *args, **kwargs)

            for arg_name, expect in arg_types.items():
                assert arg_name in call_args, 'Not found argument: %s' % arg_name
                actual = call_args[arg_name]
                if not _check_type(actual, expect):
                    raise TypeError(arg_msg % (arg_name, _get_name(expect), type(actual).__name__))

            ret = func(*args, **kwargs)
            if return_type:
                if not _check_type(ret, return_type[0]):
                    raise TypeError(return_msg % (_get_name(return_type[0]), type(ret).__name__))
            return ret

        return wrapper

    return f