docs: def batch(iterable, n, fillvalue=None):
      """Batches the elements of given iterable.
  
      Resulting iterable will yield tuples containing at most ``n`` elements
      (might be less if ``fillvalue`` isn't specified).
  
      :param n: Number of items in every batch
      :param fillvalue: Value to fill the last batch with. If None, last batch
                        might be shorter than ``n`` elements
  
      :return: Iterable of batches
  
      .. note::
  
          This is an extended version of grouper() recipe
          from the :module:`itertools` module documentation.
      """
      ensure_iterable(iterable)
      if not isinstance(n, Integral):
          raise TypeError("invalid number of elements in a batch")
      if not (n > 0):
          raise ValueError("number of elements in a batch must be positive")
  
      # since we must use ``izip_longest``
      # (``izip`` fails if ``n`` is greater than length of ``iterable``),
      # we will apply some 'trimming' to resulting tuples if necessary
      if fillvalue is None:
          fillvalue = object()
          trimmer = lambda item: tuple(x for x in item if x is not fillvalue)
      else:
          trimmer = identity()
  
      args = [iter(iterable)] * n
      zipped = izip_longest(*args, fillvalue=fillvalue)
      return imap(trimmer, zipped)