code: def types(*return_type, **arg_types):
      
      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
docs: 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)