docs: def gen_batches(iterable, batch_size):
      '''
      Returns a generator object that yields batches from `iterable`.
      See `iter_batches` for more details and caveats.
  
      Note that `iter_batches` returns an iterator, which never supports `len()`,
      `gen_batches` returns an iterable which supports `len()` if and only if
      `iterable` does. This *may* be an iterator, but could be a `SizedGenerator`
      object. To obtain an iterator (for example, to use the `next()` function),
      call `iter()` on this iterable.
  
      >>> batches = gen_batches('abcdefghijkl', batch_size=5)
      >>> len(batches)
      3
      >>> for batch in batches:
      ...     print(list(batch))
      ['a', 'b', 'c', 'd', 'e']
      ['f', 'g', 'h', 'i', 'j']
      ['k', 'l']
      '''
      def batches_thunk():
          return iter_batches(iterable, batch_size)
  
      try:
          length = len(iterable)
      except TypeError:
          return batches_thunk()
  
      num_batches = (length - 1) // batch_size + 1
      return SizedGenerator(batches_thunk, length=num_batches)