<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def iterate(self, start_line=None, parse_attr=True, headers=False, comments=False):
 """Iterate over GFF3 file, returning GFF3 entries Args: start_line (str):
 Next GFF3 entry. If 'handle' has been partially read and you want to start iterating at the next entry, read the next GFF3 entry and pass it to this variable when calling gff3_iter. See 'Examples' for proper usage. parse_attr (bool):
 Parse attributes column into a dictionary such that the string "tag1=value1;tag2=value2" becomes: tag1: value1 tag2: value2 headers (bool):
 Yields headers if True, else skips lines starting with "##" comments (bool):
 Yields comments if True, else skips lines starting with "#" Yields: GFF3Entry: class containing all GFF3 data, yields str for headers if headers options is True then yields GFF3Entry for entries Examples: The following three examples demonstrate how to use gff3_iter. Note: These doctests will not pass, examples are only in doctest format as per convention. bio_utils uses pytests for testing. """


        handle = self.handle

        # Speed tricks: reduces function calls
        split = str.split
        strip = str.strip

        if start_line is None:
            line = next(handle)  # Read first GFF3
        else:
            line = start_line  # Set header to given header

        # Check if input is text or bytestream
        if (isinstance(line, bytes)):
            def next_line(i):
                return next(i).decode('utf-8')

            line = strip(line.decode('utf-8'))
        else:
            next_line = next
            line = strip(line)

        # Manual 'for' loop isn't needed to read the file properly and quickly,
        # unlike fasta_iter and fastq_iter, but it is necessary begin iterating
        # partway through a file when the user gives a starting line.
        try:  # Manually construct a for loop to improve speed by using 'next'

            while True:  # Loop until StopIteration Exception raised

                self.current_line += 1

                data = GFF3Entry()  # Initialize early to prevent access error

                if line.startswith('##FASTA'):  # Skip FASTA entries
                    raise FastaFound

                if line.startswith('##') and not headers:
                    line = strip(next_line(handle))
                    continue
                elif line.startswith('##') and headers:
                    yield line
                    line = strip(next_line(handle))
                    continue

                if line.startswith('#') and not comments:
                    line = strip(next_line(handle))
                    continue
                elif line.startswith('#') and comments:
                    yield line
                    line = strip(next_line(handle))
                    continue

                split_line = split(line, '\t')

                data.origline = line
                data.seqid = split_line[0]
                data.source = split_line[1]
                data.type = split_line[2]
                data.start = int(split_line[3])
                data.end = int(split_line[4])
                try:  # Make float unless dot
                    data.score = float(split_line[5])
                except ValueError:
                    data.score = split_line[5]
                data._score_str = split_line[5]
                data.strand = split_line[6]
                try:  # Get phase as int unless phase not given
                    data.phase = int(split_line[7])
                except ValueError:
                    data.phase = split_line[7]
                data.attributes = split_line[8]

                if parse_attr:
                    attributes = split(data.attributes, ';')
                    data.attributes = OrderedDict()
                    for attribute in attributes:
                        split_attribute = attribute.split('=')
                        key = split_attribute[0]
                        value = split_attribute[-1].split(',') if ',' in \
                                split_attribute[-1] else split_attribute[-1]
                        if not key == '':  # Avoid semicolon split at end
                            data.attributes[key] = value

                line = strip(next_line(handle))  # Raises StopIteration at EOF

                yield data

        except StopIteration:  # Yield last GFF3 entry
            if data.origline:
                yield data
            else:  #handle case where GFF ends in comment
                pass
        except FastaFound:  # When FASTA found, last entry is repeat so pass
            pass