# Python Bio Strings

> DNA/RNA as Python strings: reverse complement (maketrans/translate), GC content, codon split, motif find (find/re.finditer), FASTA header parsing. Use for reverse complement, transcription, motif counting without Biopython.

- Skill: `pavel-kravchenko/python-bio-strings` (Agent Skill)
- Install (CLI): `npx skillmds@latest add pavel-kravchenko/python-bio-strings`
- Raw SKILL.md: https://api.skillmd.com/api/skills/pavel-kravchenko/python-bio-strings/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: pavel-kravchenko (https://skillmd.com/u/pavel-kravchenko)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/pavel-kravchenko/python-bio-strings

---


# Python Strings for Bioinformatics

## When to Use

- Writing a quick reverse-complement, transcription, or codon-splitting function without pulling in Biopython.
- Computing GC content, nucleotide composition, or motif/codon counts from raw sequence strings.
- Parsing FASTA/UniProt headers (`>sp|P04637|P53_HUMAN ...`) into accession/description fields.
- Finding all (possibly overlapping) occurrences of a motif, or IUPAC-ambiguous patterns via regex.
- Debugging why a slice or `.count()` gave the wrong answer against 1-based genomic coordinates (GFF/VCF).

## Version Compatibility

Pure standard library — Python ≥3.8 (f-strings with `=`, `str.maketrans`/`translate` are stable since Python 3). No external packages required. For anything beyond ad-hoc string ops (parsing real FASTA files, alphabet validation, translation tables), switch to `Bio.Seq`/`Bio.SeqIO` from Biopython ≥1.78 — see `python-bio-sequences`.

## Prerequisites

- Comfort with Python string slicing (`seq[start:stop:step]`) and list comprehensions.
- No packages to install — this is stdlib only (`re` for regex patterns).

## Core Patterns

**Goal:** compute a reverse complement, transcribe DNA→RNA, and split into codons correctly.
**Approach:** use `str.maketrans` + `translate()` for complementing (never chained `replace()` — see Pitfalls), then reverse with `[::-1]`.

```python
def reverse_complement(dna: str) -> str:
    """Return the reverse complement of a DNA string (uppercase A/T/G/C only)."""
    complement_table = str.maketrans('ATGC', 'TACG')
    return dna.upper().translate(complement_table)[::-1]

def transcribe(dna_coding_strand: str) -> str:
    """Transcribe a DNA coding strand to mRNA (T -> U)."""
    return dna_coding_strand.upper().replace('T', 'U')

def gc_content(seq: str) -> float:
    """Fraction of G/C bases in seq, case-insensitive."""
    seq = seq.upper()
    return (seq.count('G') + seq.count('C')) / len(seq)

def codons(mrna: str) -> list[str]:
    """Split an mRNA/coding sequence into non-overlapping codons."""
    return [mrna[i:i + 3] for i in range(0, len(mrna), 3)]

dna = "ATGCGATCGATCGTAG"
assert reverse_complement(dna) == "CTACGATCGATCGCAT"
assert transcribe(dna) == "AUGCGAUCGAUCGUAG"
assert round(gc_content(dna), 2) == 0.5
assert codons("AUGGCCGAUUAG") == ["AUG", "GCC", "GAU", "UAG"]
```

**Goal:** find all motif occurrences (including overlaps) and IUPAC-ambiguous patterns.
**Approach:** `str.find()` in a loop for overlapping literal matches; `re.finditer` for ambiguous/IUPAC motifs (e.g. TATA box `TATA[AT]A[AT]`).

```python
import re

def find_all(seq: str, motif: str) -> list[int]:
    """Return all start positions of motif in seq, including overlapping matches."""
    positions = []
    pos = seq.find(motif)
    while pos != -1:
        positions.append(pos)
        pos = seq.find(motif, pos + 1)
    return positions

def find_tata_boxes(seq: str) -> list[tuple[int, str]]:
    """Find TATA-box-like elements (TATA[AT]A[AT]) and their start positions."""
    return [(m.start(), m.group()) for m in re.finditer(r'TATA[AT]A[AT]', seq)]

assert find_all("AAAA", "AA") == [0, 1, 2]          # overlapping: 3 hits
assert "AAAA".count("AA") == 2                       # count() is non-overlapping
assert find_tata_boxes("NNTATAAAANN") == [(2, 'TATAAAA')]
```

**Goal:** parse a UniProt/NCBI-style FASTA header into its fields.
**Approach:** split on `|` for UniProt (`db|accession|entry_name description`), or on whitespace for simple `>id description` headers.

```python
def parse_uniprot_header(header: str) -> dict:
    """Parse a '>sp|ACCESSION|ENTRY_NAME description' UniProt FASTA header."""
    body = header.lstrip('>')
    db, accession, rest = body.split('|', 2)
    entry_name, _, description = rest.partition(' ')
    return {"db": db, "accession": accession, "entry_name": entry_name, "description": description}

header = ">sp|P04637|P53_HUMAN Cellular tumor antigen p53 OS=Homo sapiens"
parsed = parse_uniprot_header(header)
assert parsed["accession"] == "P04637"
assert parsed["entry_name"] == "P53_HUMAN"
```

## Sequence Features

```python
seq = "ATGGCCGATTAGCCA"

seq.startswith('ATG')                 # has start codon
seq[-3:] in ('TAA', 'TAG', 'TGA')     # ends with stop codon
'GATTAG' in seq                       # motif membership
all(c in 'ATGC' for c in seq.upper()) # validate DNA alphabet
```

## Pitfalls

- **Chained `replace()` fails for complement**: `dna.replace('A','T').replace('T','A')` converts all A→T then all T→A, including the ones just created — every base ends up A. Use `str.maketrans` + `translate()`.
- **`find()` returns -1, not None**: `if pos:` is truthy for -1 (and falsy only for 0, a valid match at the start). Always check `if pos != -1:`.
- **`count()` is non-overlapping**: `"AAAA".count("AA")` = 2, not 3. Use the `find()`-loop pattern above for overlapping matches.
- **Case sensitivity**: `.count('G')` misses lowercase 'g' (common in soft-masked repeat sequences). Always `.upper()` first.
- **Strings are immutable**: `seq[0] = 'C'` raises `TypeError`. Build new strings with slicing/concatenation, `str.translate`, or `''.join(...)`.
- **Bioinformatics coordinates are 1-based, inclusive**: GFF/VCF/SAM position 100 is Python index 99; a 1-based inclusive range `[start, end]` becomes the Python slice `seq[start-1:end]`.

## See Also

- `python-bio-sequences` — Biopython `Seq`/`SeqRecord` objects for real FASTA/GenBank I/O and translation tables.
- `python-bio-regular-expressions` — regex patterns for IUPAC ambiguity codes, restriction sites, and complex motifs.
- `python-bio-lists` — list/slice mechanics that underlie codon splitting and k-mer windows.
- `bio-core-motif-discovery` — motif discovery and enrichment beyond literal/regex matching.

