| name | python-bio-operators |
| description | Apply //, %, and 'in' operators to DNA/protein data — codon math, reading frames, GC precedence, stop-codon lookups. Use when computing GC content, finding reading frames, filtering by QC, or fixing precedence bugs. |
| tool_type | python |
| primary_tool | python |
Python Operators for Bioinformatics
When to Use
- Computing GC content, codon counts, or reading frames from sequence lengths/positions
- Filtering sequences by multiple QC criteria (length, GC%, ambiguous bases) in one expression
- Checking membership — is a codon a stop codon, is a base valid, is a key in a codon table
- Debugging a wrong GC% or Tm calculation caused by operator precedence (
g + c / total * 100)
- Choosing
== vs is, or list vs set membership, for repeated sequence/codon lookups
Version Compatibility
Python ≥3.8 (f-strings). No external packages required — pure built-in operators.
Prerequisites
- Basic Python: variables, strings, lists, dicts, sets, functions
- No other skill required; this is foundational for
python-bio-strings, python-bio-sequences
Codon Arithmetic and Reading Frames
Goal: Given a sequence length or a position, get the number of complete codons, leftover
bases, and which of the three reading frames a position falls in.
Approach: // (floor division) always returns an int and gives complete units; /
always returns a float. % gives the remainder, which doubles as the reading-frame index.
def codon_stats(seq_length: int, position: int = 0) -> dict:
"""Return codon-counting stats for a sequence length and a query position.
seq_length // 3 -> number of complete codons (int, not float — use // not /)
seq_length % 3 -> leftover nucleotides after the last complete codon
position % 3 -> reading frame (0, 1, or 2) that `position` falls in
"""
return {
"complete_codons": seq_length // 3,
"leftover_nucleotides": seq_length % 3,
"reading_frame": position % 3,
}
stats = codon_stats(seq_length=1000, position=47)
print(stats)
GC Content and Multi-Criteria Sequence Filtering
Goal: Compute GC content without a precedence bug, then combine it with length and
ambiguous-base checks in a single readable boolean expression.
Approach: Parenthesize (g + c) explicitly — * and / bind tighter than +, so
g + c / total * 100 silently computes g + (c / total * 100). Use chained comparisons
(a <= x <= b) instead of x >= a and x <= b, and set literals for O(1) membership tests.
def gc_content(sequence: str) -> float:
"""Return GC content as a percentage. Precedence-safe: (g + c) is parenthesized."""
seq = sequence.upper()
g, c = seq.count("G"), seq.count("C")
total = len(seq)
return (g + c) / total * 100 if total else 0.0
def passes_qc(sequence: str, has_ambiguous_bases: bool = False) -> bool:
"""Multi-criteria QC filter: length 500-3000 nt, GC 30-70%, no ambiguous bases."""
seq_length = len(sequence)
gc = gc_content(sequence)
return (
500 <= seq_length <= 3000
and 30.0 <= gc <= 70.0
and not has_ambiguous_bases
)
def is_stop_codon(codon: str) -> bool:
"""O(1) membership test against a set literal (use a set, not a list, for lookups)."""
return codon.upper() in {"TAA", "TAG", "TGA"}
Primer Melting Temperature (Wallace Rule)
Goal: Estimate a short primer's melting temperature — a common downstream use of the
same arithmetic/precedence rules.
Approach: Tm = 2*(A+T) + 4*(G+C) for primers under 14 nt (Wallace rule).
def melting_temperature(primer: str) -> float:
"""Estimate Tm (degrees C) for a short PCR primer using the Wallace rule."""
p = primer.upper()
a, t, g, c = p.count("A"), p.count("T"), p.count("G"), p.count("C")
if len(p) < 14:
return 2 * (a + t) + 4 * (g + c)
return 64.9 + 41 * (g + c - 16.4) / (a + t + g + c)
Pitfalls
// vs / for codons: seq_length // 3 gives complete codons (int). / always
returns float, which breaks anything expecting an integer codon count or index.
% for reading frames: position % 3 gives the frame (0, 1, or 2); seq_length % 3
gives leftover nucleotides — don't confuse the two uses of the same operator.
- Precedence trap in GC content:
g + c / total * 100 is wrong (division binds before
+). Always write (g + c) / total * 100.
== vs is: use == for value comparison; is only for None/True/False.
Never write if x == None or if my_list is [1, 2, 3].
in checks dict keys, not values: "ATG" in codon_table checks keys. Use
"Met" in codon_table.values() to check values (and it's O(n), not O(1)).
in with sets is O(1), with lists is O(n): convert to a set before repeated
membership tests (e.g. stop-codon or valid-nucleotide checks in a loop over a chromosome).
and/or short-circuit: passes_qc(seq) and log_pass(seq) won't call log_pass if
passes_qc is False — fine for filters, a bug if the right side has required side effects.
See Also
python-bio-expressions — building larger expressions and boolean logic
python-bio-strings — string methods (.count(), .upper(), slicing) used above
python-bio-sequences — sequence objects that wrap these operations
bio-primer-design-primer-basics — full primer design beyond the Wallace-rule estimate