Трансляция: от мРНК к белку
Трансляция — превращение строки мРНК в строку белка по таблице кодонов. Один из самых наглядных алгоритмов курса.
Трансляция — синтез белка по мРНК: рибосома читает кодоны от старт-сигнала до стоп-сигнала и собирает цепочку аминокислот.
Имея таблицу кодонов из прошлого урока, написать трансляцию — дело нескольких строк. Но в деталях кроется биология: где начать, где остановиться, что делать с «хвостом». Разберём по шагам и получим настоящий белок.
Наивная трансляция всей строки
Простейший вариант: бить мРНК на тройки с начала и переводить каждую, останавливаясь на стоп-кодоне.
CODON = {
'UUU':'F','UUC':'F','UUA':'L','UUG':'L','CUU':'L','CUC':'L','CUA':'L','CUG':'L',
'AUU':'I','AUC':'I','AUA':'I','AUG':'M','GUU':'V','GUC':'V','GUA':'V','GUG':'V',
'UCU':'S','UCC':'S','UCA':'S','UCG':'S','CCU':'P','CCC':'P','CCA':'P','CCG':'P',
'ACU':'T','ACC':'T','ACA':'T','ACG':'T','GCU':'A','GCC':'A','GCA':'A','GCG':'A',
'UAU':'Y','UAC':'Y','UAA':'*','UAG':'*','CAU':'H','CAC':'H','CAA':'Q','CAG':'Q',
'AAU':'N','AAC':'N','AAA':'K','AAG':'K','GAU':'D','GAC':'D','GAA':'E','GAG':'E',
'UGU':'C','UGC':'C','UGA':'*','UGG':'W','CGU':'R','CGC':'R','CGA':'R','CGG':'R',
'AGU':'S','AGC':'S','AGA':'R','AGG':'R','GGU':'G','GGC':'G','GGA':'G','GGG':'G',
}
def translate(rna):
protein = ''
for i in range(0, len(rna) - 2, 3):
aa = CODON[rna[i:i+3]]
if aa == '*':
break
protein += aa
return protein
rna = 'AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG'
print('мРНК: ', rna)
print('Белок:', translate(rna))Вывод:
мРНК: AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG Белок: MAIVMGR
Разбор: range(0, len-2, 3) идёт по тройкам и не вылезает за конец; на стоп-кодоне (UGA здесь) перевод обрывается, поэтому белок короче, чем «вся строка делённая на 3».
Трансляция из ДНК напрямую
На практике у нас обычно ДНК, а не мРНК. Можно завести ДНК-таблицу (с T) или транскрибировать. Покажем перевод прямо из ДНК — удобно, потому что геномы хранятся в ДНК.
DNA_CODON = {
'TTT':'F','TTC':'F','TTA':'L','TTG':'L','CTT':'L','CTC':'L','CTA':'L','CTG':'L',
'ATT':'I','ATC':'I','ATA':'I','ATG':'M','GTT':'V','GTC':'V','GTA':'V','GTG':'V',
'TCT':'S','TCC':'S','TCA':'S','TCG':'S','CCT':'P','CCC':'P','CCA':'P','CCG':'P',
'ACT':'T','ACC':'T','ACA':'T','ACG':'T','GCT':'A','GCC':'A','GCA':'A','GCG':'A',
'TAT':'Y','TAC':'Y','TAA':'*','TAG':'*','CAT':'H','CAC':'H','CAA':'Q','CAG':'Q',
'AAT':'N','AAC':'N','AAA':'K','AAG':'K','GAT':'D','GAC':'D','GAA':'E','GAG':'E',
'TGT':'C','TGC':'C','TGA':'*','TGG':'W','CGT':'R','CGC':'R','CGA':'R','CGG':'R',
'AGT':'S','AGC':'S','AGA':'R','AGG':'R','GGT':'G','GGC':'G','GGA':'G','GGG':'G',
}
def translate_dna(dna):
protein = ''
for i in range(0, len(dna) - 2, 3):
aa = DNA_CODON[dna[i:i+3]]
if aa == '*':
break
protein += aa
return protein
gene = 'ATGTTTAAAGGGTGCCCGTAA'
print('Ген: ', gene)
print('Белок:', translate_dna(gene))Вывод:
Ген: ATGTTTAAAGGGTGCCCGTAA Белок: MFKGCP
Как работает под капотом: рамка считывания
Один и тот же текст ДНК даёт разные белки в зависимости от того, с какой позиции начать делить на тройки. Эти три варианта (старт 0, 1, 2) — три рамки считывания. Сдвиг на одну букву (frameshift-мутация, вставка или удаление одной буквы) полностью меняет белок ниже точки сдвига — поэтому такие мутации часто катастрофичны. Проверим, как меняется перевод при сдвиге старта.
DNA_CODON = {'ATG':'M','TTT':'F','TGA':'*','GAT':'D','GTT':'V','ATT':'I','TTG':'L'}
def translate_from(dna, start):
out = ''
for i in range(start, len(dna) - 2, 3):
aa = DNA_CODON.get(dna[i:i+3], '?')
if aa == '*':
break
out += aa
return out
dna = 'ATGTTTGA'
for frame in range(3):
print(f'рамка {frame}:', translate_from(dna, frame))Вывод:
рамка 0: MF рамка 1: ?L рамка 2: V
Три рамки дали три совершенно разных результата: MF, ?L и V (вопрос — кодон не из нашего урезанного словаря). Это иллюстрирует, насколько выбор рамки решающий: одна и та же ДНК читается тремя способами, и лишь один обычно «настоящий». Поиск правильной рамки — тема следующего урока про ORF.
Здесь скрыт важный для медицины момент. Мутации, которые добавляют или удаляют число букв, не кратное трём, вызывают сдвиг рамки (frameshift), и весь белок ниже точки сдвига превращается в бессмыслицу — чаще всего вскоре натыкается на случайный стоп-кодон и обрывается. Поэтому вставка или удаление одной-двух букв обычно куда губительнее, чем замена одной буквы: замена меняет максимум одну аминокислоту, а сдвиг рамки уничтожает всю оставшуюся часть белка. Многие тяжёлые наследственные заболевания вызваны именно frameshift-мутациями. А вот вставка или удаление ровно трёх букв сохраняет рамку и просто добавляет или убирает одну аминокислоту — последствия обычно мягче. Эта арифметика «кратно ли трём» — то, что биоинформатик первым делом проверяет, оценивая инсерцию или делецию.
Частые ошибки
- Не останавливаться на стопе. Без проверки на '*' вы переведёте мусор после конца белка.
- Игнорировать неполный хвост. Если длина не кратна 3, последние 1–2 буквы — не кодон;
range(0, len-2, 3)их отбрасывает. - Перепутать ДНК и РНК-таблицу. T против U — частый источник KeyError.
Итог
- Трансляция — разбиение мРНК на кодоны и перевод по таблице до стоп-сигнала.
- Удобно
range(0, len-2, 3)для тройки и обрыв на '*'. - Транслировать можно прямо из ДНК, заведя таблицу с T.
- Выбор рамки считывания критичен: сдвиг на одну букву меняет весь белок ниже точки сдвига.