Транскрипция и сборка базовых операций

Соберём изученное в маленький набор инструментов: длина, состав, комплемент, транскрипция — кирпичики для всего дальнейшего.

Транскрипция в коде — преобразование строки ДНК в строку мРНК заменой каждого тимина (T) на урацил (U).

По отдельности базовые операции мы уже видели. Этот урок показывает, как их связать в осмысленный конвейер и аккуратно учесть, что у ДНК две нити — а значит, транскрибировать можно с любой из них.

Транскрипция в коде

Если ген на плюс-нити, мРНК — это просто ДНК с заменой T→U. Но клетка синтезирует РНК по матричной (template) нити, и итоговая мРНК совпадает с кодирующей нитью. Для нас на уровне строк важно одно правило: T→U на кодирующей нити.

def transcribe(dna):
    return dna.upper().replace("T", "U")

coding = "ATGGCCTAA"
print("Кодирующая ДНК:", coding)
print("мРНК:          ", transcribe(coding))

Вывод:

Кодирующая ДНК: ATGGCCTAA
мРНК:           AUGGCCUAA

Транскрипция с матричной нити

Если вам дана матричная (template) нить, мРНК — это её обратный комплемент с U вместо T. Учтём это явно, чтобы не запутаться, какая нить дана.

pairs = {"A": "U", "T": "A", "G": "C", "C": "G"}

def mrna_from_template(template):
    # мРНК синтезируется комплементарно матричной нити
    return "".join(pairs[b] for b in reversed(template))

template = "TTAGGCCAT"
print("Матричная нить:", template)
print("мРНК:          ", mrna_from_template(template))

Вывод:

Матричная нить: TTAGGCCAT
мРНК:           AUGGCCUAA

Обе дороги привели к одной мРНК AUGGCCUAA — потому что матричная нить была обратным комплементом кодирующей. Понимание этой симметрии спасает от путаницы.

Мини-инструментарий

Сложим базовые функции вместе — это «швейцарский нож» для последовательностей, на который мы будем опираться дальше.

rc_table = str.maketrans("ATGC", "TACG")

def length(seq):
    return len(seq)

def gc(seq):
    s = seq.upper()
    return (s.count("G") + s.count("C")) / len(s) * 100

def reverse_complement(seq):
    return seq.upper().translate(rc_table)[::-1]

def transcribe(seq):
    return seq.upper().replace("T", "U")

dna = "ATGCGTACG"
print("Длина:              ", length(dna))
print("GC-состав:          ", f"{gc(dna):.1f}%")
print("Обратный комплемент:", reverse_complement(dna))
print("мРНК:               ", transcribe(dna))

Вывод:

Длина:               9
GC-состав:           55.6%
Обратный комплемент: CGTACGCAT
мРНК:                AUGCGUACG

Как работает под капотом: одна нить — два смысла

Каждый участок генома можно прочитать в шести «рамках»: три на плюс-нити и три на минус-нити (через обратный комплемент). Поэтому при поиске генов всегда рассматривают обе нити. Наш reverse_complement — ровно тот инструмент, что даёт доступ ко второй нити; рамки считывания разберём в следующем разделе.

Полезно отрефлексировать, что мы только что собрали мини-библиотеку, и оценить её устойчивость. Все четыре функции принимают строку и возвращают строку или число — они чистые (без побочных эффектов), а значит, легко тестируются и комбинируются. Но у них есть скрытое допущение: вход состоит только из ATGC. Функция reverse_complement на базе str.translate устойчива — неизвестные символы она просто оставит как есть, — а вот вариант со словарём упал бы по KeyError на букве N. В продакшен-коде такие допущения делают явными: либо валидируют вход на границе системы (как мы делали в разделе про строки), либо расширяют таблицы, чтобы корректно обрабатывать N и IUPAC-символы. Привычка с самого начала думать «а что если на входе грязь» отличает учебный код от рабочего.

Частые ошибки

  • Транскрибировать, не определив нить. Дана кодирующая или матричная? От этого зависит, нужен ли обратный комплемент.
  • Оставить T в мРНК. После транскрипции T быть не должно.
  • Смешивать алфавиты. В функциях для РНК таблица пар использует U, в ДНК — T.

Связав воедино транскрипцию, GC-состав и обратный комплемент, мы фактически реализовали в миниатюре то, что делают «солдатские» утилиты биоинформатики вроде пакета EMBOSS или модулей Biopython: дай последовательность — получи её базовые характеристики и преобразования. Разница в том, что промышленные инструменты обрабатывают терабайты, поддерживают десятки форматов и учитывают тысячу краевых случаев. Но идейно внутри них — ровно те же строковые операции, что мы написали на двух десятках строк stdlib. Это важный вывод раздела: биоинформатика не магия, а аккуратная инженерия над строками; поняв базовые кирпичики, вы понимаете и то, что прячут готовые библиотеки, и можете при необходимости заглянуть внутрь или собрать своё.

Итог

  • Транскрипция кодирующей нити — замена T→U; с матричной нити — обратный комплемент с U.
  • Обе пути дают одну мРНК, потому что нити комплементарны.
  • Базовые функции (длина, GC, обратный комплемент, транскрипция) образуют переиспользуемый инструментарий.
  • Любой участок читается в шести рамках (две нити × три сдвига) — основа поиска генов.
Проверьте себя
1. Как из кодирующей нити ДНК получить мРНК на уровне строк?
AПеревернуть строку
BЗаменить каждый T на U
CВзять обратный комплемент
DЗаменить A на U
2. Сколько рамок считывания у участка ДНК с учётом обеих нитей?
A1
B2
C3
D6
3. Если дана матричная (template) нить, как получить мРНК?
AПросто заменить T на U
BВзять обратный комплемент и использовать U вместо T
CОставить как есть
DУдвоить строку