class_docstr: Iterator for sharding batch into num_shards batches.
  
  Args:
      batch: The input multi-agent batch.
      num_shards: The number of shards to split the batch into.
  
  Yields:
      A MultiAgentBatch of size len(batch) / num_shards.
code: def __iter__(self):
      for i in range(self._num_shards):
          batch_to_send = {}
          for pid, sub_batch in self._batch.policy_batches.items():
              batch_size = math.ceil(len(sub_batch) / self._num_shards)
              start = batch_size * i
              end = min(start + batch_size, len(sub_batch))
              batch_to_send[pid] = sub_batch[int(start) : int(end)]
          # TODO (Avnish): int(batch_size) ? How should we shard MA batches really?
          new_batch = MultiAgentBatch(batch_to_send, int(batch_size))
          yield new_batch
  
imports: import math
  from typing import List
  from ray.rllib.policy.sample_batch import MultiAgentBatch, concat_samples
  from ray.rllib.policy.sample_batch import SampleBatch
  from ray.rllib.utils.annotations import DeveloperAPI
  from ray.rllib.utils.typing import EpisodeType
label_desc: Use image node_id 2 for calling the ShardBatchIterator obj's underlying member method code with example usage: obj.__iter__() without return types