<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def search_reads( self, read_group_ids, reference_id=None, start=None, end=None):
 """ Returns an iterator over the Reads fulfilling the specified conditions from the specified read_group_ids. :param str read_group_ids: The IDs of the :class:`ga4gh.protocol.ReadGroup` of interest. :param str reference_id: The name of the :class:`ga4gh.protocol.Reference` we wish to return reads mapped to. :param int start: The start position (0-based) of this query. If a reference is specified, this defaults to 0. Genomic positions are non-negative integers less than reference length. Requests spanning the join of circular genomes are represented as two requests one on each side of the join (position 0). :param int end: The end position (0-based, exclusive) of this query. If a reference is specified, this defaults to the reference's length. :return: An iterator over the :class:`ga4gh.protocol.ReadAlignment` objects defined by the query parameters. :rtype: iter """

        request = protocol.SearchReadsRequest()
        request.read_group_ids.extend(read_group_ids)
        request.reference_id = pb.string(reference_id)
        request.start = pb.int(start)
        request.end = pb.int(end)
        request.page_size = pb.int(self._page_size)
        return self._run_search_request(
            request, "reads", protocol.SearchReadsResponse)