Before you start
You've met FASTA/FASTQ in lesson 1 and can run Python. In Colab, start each notebook with !pip install biopython.
Learning objectives
By the end of this lesson you will be able to: create a Biopython Seq object and use its biology-aware methods, read sequence files with SeqIO.parse, filter records to keep only the ones you want, and write your results back out to a file.
The one import to remember
Biopython gives you two workhorses: the Seq object (a sequence with biology-aware methods) and SeqIO (read/write sequence files). Almost everything starts with these.
from Bio.Seq import Seq from Bio import SeqIO
The Seq object: a sequence that knows biology
A plain Python string can't transcribe or translate itself. A Biopython Seq can.
dna = Seq("ATGGCCCTGTGGATGCGCTAA") print(len(dna)) # length print(dna.complement()) # pair each base (AโT, GโC) print(dna.reverse_complement()) # the other strand, read 5'โ3' print(dna.transcribe()) # DNA โ RNA (T becomes U) print(dna.translate()) # RNA/DNA โ protein (amino acids)
Decode the jargon: reverse complement
DNA is double-stranded. If one strand reads ATGC, the partner strand reads GCAT (complement each base, then reverse the order). You need the reverse complement constantly - for example, when a gene sits on the opposite strand. Biopython does it in one call.
SeqIO: reading files (the pattern that scales)
Two methods cover almost everything. SeqIO.read() for a file with one record; SeqIO.parse() for a file with many.
# make a multi-record FASTA to work with with open("genes.fasta", "w") as f: f.write(">insulin\nATGGCCCTGTGGATGCGCCTC\n") f.write(">globin\nATGGTGCATCTGACTCCTGAG\n") f.write(">short\nATGAAA\n") for rec in SeqIO.parse("genes.fasta", "fasta"): print(rec.id, len(rec.seq), "bp")
Each rec is a SeqRecord - a sequence plus its metadata: rec.id (the name), rec.description, and rec.seq (the Seq itself).
Manipulate: filter records
A real task: keep only the records longer than some cutoff. Just loop and test.
keep = [rec for rec in SeqIO.parse("genes.fasta", "fasta") if len(rec.seq) >= 15] print("Kept", len(keep), "of 3 records")
Write: save your results
Whatever records you've kept or changed, SeqIO.write() saves them back to a file in any format.
SeqIO.write(keep, "filtered.fasta", "fasta") print("Saved filtered.fasta")
That's the full cycle - read โ manipulate โ write - and it's the backbone of countless real scripts. You now have the tools to process a sequence file of any size.
๐ Make it your own
- Print the reverse complement of each record in
genes.fasta. - Translate each sequence to protein and print the result (remember a clean coding sequence is a multiple of 3).
- Write only the records whose ID contains "globin" to a new file.
- Convert
genes.fastato a different format in one line:SeqIO.convert("genes.fasta","fasta","genes.tab","tab").
Check your understanding
SeqIO.read() vs SeqIO.parse()?read() for a file with exactly one record (it returns that single record); parse() for a file with one or many (it returns an iterator you loop over)..id, .description, and other annotations - wrapped around the .seq. A Seq is just the letters; a SeqRecord is the letters plus their label.complement, reverse_complement, transcribe, translate. A plain string can't do those.SeqIO.write() writes records to a file in whatever format you name, completing the read, manipulate, write cycle.reverse_complement() return?reverse_complement() gives the opposite strand: it complements each base (A with T, G with C) and reverses the order. You need it constantly when a gene sits on the other strand.