class_docstr: DataIterator
  Collect data from `data_source` and yields bunch of data.
  
  Args:
      data_source (:py:class:`DataSource <nnabla.utils.data_source.DataSource>`):
           Instance of DataSource class witch provides data for this class.
      batch_size (int): Size of data unit.
      rng (None or :obj:`numpy.random.RandomState`): Numpy random number
          generator.
      use_thread (bool): If ``use_thread`` is set to True, iterator will use another
          thread to fetch data. If ``use_thread`` is set to False, iterator will use
          current thread to fetch data.
      epoch_begin_callbacks (list of functions): An item is a function
          which takes an epoch index as a argument. These are called
          at the beginning of an epoch.
      epoch_end_callbacks (list of functions): An item is a function
          which takes an epoch index as a argument. These are called
          at the end of an epoch.
      stop_exhausted (bool): If ``stop_exhausted`` is set to False, iterator will be reset
          so that iteration can be continued. If ``stop_exhausted`` is set to True, iterator
          will raise StopIteration to stop the loop.
docstr: Slices the data iterator so that newly generated data iterator has access to limited portion of the original data.
  
  Args:
      rng (numpy.random.RandomState): Random generator for Initializer.
      num_of_slices(int): Total number of slices to be made. Muts be used together with `slice_pos`. 
      slice_pos(int): Position of the slice to be assigned to the new data iterator. Must be used together with `num_of_slices`.
      slice_start(int): Starting position of the range to be sliced into new data iterator. Must be used together with `slice_end`.
      slice_end(int) : End position of the range to be sliced into new data iterator. Must be used together with `slice_start`.
      cache_dir(str) : Directory to save cache files. if cache_dir is None and use_cache is True, will used memory cache.
      use_cache(bool): Whether use cache for data_source.
      drop_last(bool): If it is True, the samples if the number of samples cannot be evenly divisible are dropped,
                       If it is False, the samples are duplicated so that it is evenly divisible.
  
  Example:
  
  .. code-block:: python
  
      from nnabla.utils.data_iterator import data_iterator_simple
      import numpy as np
  
      def load_func1(index):
          d = np.ones((2, 2)) * index
          return d
  
      di = data_iterator_simple(load_func1, 1000, batch_size=3)
  
      di_s1 = di.slice(None, num_of_slices=10, slice_pos=0)
      di_s2 = di.slice(None, num_of_slices=10, slice_pos=1)
  
      di_s3 = di.slice(None, slice_start=100, slice_end=200)
      di_s4 = di.slice(None, slice_start=300, slice_end=400) 
code: def slice(
      self,
      rng,
      num_of_slices=None,
      slice_pos=None,
      slice_start=None,
      slice_end=None,
      cache_dir=None,
      use_cache=False,
      drop_last=False,
  ):
      """
      Slices the data iterator so that newly generated data iterator has access to limited portion of the original data.
  
      Args:
          rng (numpy.random.RandomState): Random generator for Initializer.
          num_of_slices(int): Total number of slices to be made. Muts be used together with `slice_pos`.
          slice_pos(int): Position of the slice to be assigned to the new data iterator. Must be used together with `num_of_slices`.
          slice_start(int): Starting position of the range to be sliced into new data iterator. Must be used together with `slice_end`.
          slice_end(int) : End position of the range to be sliced into new data iterator. Must be used together with `slice_start`.
          cache_dir(str) : Directory to save cache files. if cache_dir is None and use_cache is True, will used memory cache.
          use_cache(bool): Whether use cache for data_source.
          drop_last(bool): If it is True, the samples if the number of samples cannot be evenly divisible are dropped,
                           If it is False, the samples are duplicated so that it is evenly divisible.
  
      Example:
  
      .. code-block:: python
  
          from nnabla.utils.data_iterator import data_iterator_simple
          import numpy as np
  
          def load_func1(index):
              d = np.ones((2, 2)) * index
              return d
  
          di = data_iterator_simple(load_func1, 1000, batch_size=3)
  
          di_s1 = di.slice(None, num_of_slices=10, slice_pos=0)
          di_s2 = di.slice(None, num_of_slices=10, slice_pos=1)
  
          di_s3 = di.slice(None, slice_start=100, slice_end=200)
          di_s4 = di.slice(None, slice_start=300, slice_end=400)
  
      """
  
      def get_slice_start_end(size, n_slices, rank):
          """
          This algorithm tends to evenly assign the remained to
          each slice block with some integer tricky.
          """
          if drop_last:
              size_rank = size // n_slices
              slice_start = size_rank * rank
              slice_end = slice_start + size_rank
          else:
              size_rank = (size + n_slices - 1) // n_slices
              slice_start = (size_rank * rank) % size
              slice_end = slice_start + size_rank
              if slice_end > size:
                  offset = slice_end - size
                  slice_end -= offset
                  slice_start -= offset
  
          return slice_start, slice_end
  
      if (
          num_of_slices is not None
          and slice_pos is not None
          and slice_start is None
          and slice_end is None
      ):
          slice_start, slice_end = get_slice_start_end(
              self._size, num_of_slices, slice_pos
          )
      elif (
          num_of_slices is None
          and slice_pos is None
          and slice_start is not None
          and slice_end is not None
      ):
          pass
      else:
          logger.critical(
              "You must specify position(num_of_slice and slice_pos) or range(slice_start and slice_end)."
          )
          return None
  
      if cache_dir is None:
          ds = self._data_source
          while "_data_source" in dir(ds):
              if "_cache_dir" in dir(ds):
                  cache_dir = ds._cache_dir
              ds = ds._data_source
  
      if use_cache:
          if cache_dir is None:
              return DataIterator(
                  DataSourceWithMemoryCache(
                      SlicedDataSource(
                          self._data_source,
                          self._data_source.shuffle,
                          slice_start=slice_start,
                          slice_end=slice_end,
                      ),
                      shuffle=self._shuffle,
                      rng=rng,
                  ),
                  self._batch_size,
              )
          else:
              return DataIterator(
                  DataSourceWithMemoryCache(
                      DataSourceWithFileCache(
                          SlicedDataSource(
                              self._data_source,
                              self._data_source.shuffle,
                              slice_start=slice_start,
                              slice_end=slice_end,
                          ),
                          cache_dir=cache_dir,
                          cache_file_name_prefix="cache_sliced_{:08d}_{:08d}".format(
                              slice_start, slice_end
                          ),
                          shuffle=self._shuffle,
                          rng=rng,
                      ),
                      shuffle=self._shuffle,
                      rng=rng,
                  ),
                  self._batch_size,
              )
      else:
          return DataIterator(
              SlicedDataSource(
                  self._data_source,
                  self._data_source.shuffle,
                  slice_start=slice_start,
                  slice_end=slice_end,
              ),
              self._batch_size,
          )
  
imports: import atexit
  import threading
  import queue
  import numpy
  import six
  from nnabla.logger import logger
  from .data_source import DataSourceWithFileCache
  from .data_source import DataSourceWithMemoryCache
  from .data_source import SlicedDataSource
  from .data_source_implements import CacheDataSource
  from .data_source_implements import ConcatDataSource
  from .data_source_implements import CsvDataSource
  from .data_source_implements import SimpleDataSource
label_desc: Use image node_id 15 for calling the DataIterator obj's underlying member method code with example usage: obj.slice(rng, num_of_slices, slice_pos, slice_start, slice_end, cache_dir, use_cache, drop_last) and returns: slice_start,  slice_end, DataIterator, None, DataIterator, DataIterator