Синтез ДНК кажется чем-то сугубо биологическим — с пробирками, центрифугами и белыми халатами. Но что, если попробовать собрать ДНК в коде? Не просто сгенерировать последовательность, а симулировать реальные процессы: лигирование, гибридизацию, ПЦР, ошибочные вставки, ферментативные сдвиги и многое другое. В этой статье — практическая попытка воссоздать молекулярную биологию средствами Python, без библиотек типа Biopython, с нуля. Много кода, немного шуток и один вопрос — можно ли построить in silico ДНК-лабораторию?

Слова “биоинформатика” и “программирование” обычно встречаются в одном предложении, когда речь идёт о парсинге геномов, анализе экспрессии генов или машинном обучении для диагностики. Но однажды захотелось большего. Хотелось не просто читать гены, а играть с ними. Моделировать их, собирать руками. Вернее, клавиатурой.
Идея: построить в коде лабораторную скамью, где можно будет “сшивать” фрагменты ДНК, копировать их, проверять на ошибки. Причём без привычных библиотек вроде Biopython — просто Python, NumPy и желание воссоздать реальный молекулярный процесс в виртуальной среде. Можно ли собрать виртуальную ДНК-плазмиду и отдать её синтетической биологии?
Да. Но сначала немного теории.
Минимум молекулярной биологии
Если вы не биолог — не страшно. Вот краткий набор знаний, который понадобится:
-
ДНК состоит из 4 оснований:
A,T,C,G. -
Aсоединяется сT,CсG. Это называется комплементарностью. -
ДНК может быть одноцепочечной или двуцепочечной.
-
Ферменты могут копировать, соединять, резать или модифицировать ДНК.
-
Сборка ДНК — это как LEGO, только меньше и с более странными инструкциями.
Соберём свой набор инструментов.
1. Структура: последовательности и цепи
Начнём с основного объекта — молекулы ДНК. Представим её как последовательность символов, но добавим немного структуры.
Язык: Python 3.11+
from typing import List class Strand: def __init__(self, sequence: str): assert all(base in "ATCG" for base in sequence), "Invalid DNA sequence" self.sequence = sequence def complement(self) -> str: return self.sequence.translate(str.maketrans("ATCG", "TAGC")) def reverse_complement(self) -> str: return self.complement()[::-1] def __repr__(self): return f"5'-{self.sequence}-3'"
Пример использования:
s = Strand("ATGCGT") print(s.reverse_complement()) # ACGCAT
Класс Strand — это строительный кирпич. Теперь можно моделировать гибридизацию, сшивку и другие операции.
2. Гибридизация: связываем цепи
Когда две цепи встречаются и могут быть комплементарными, они связываются — образуется “дуплекс”.
def can_hybridize(s1: Strand, s2: Strand, min_overlap: int = 5) -> bool: rc = s2.reverse_complement() for i in range(len(s1.sequence) - min_overlap + 1): if s1.sequence[i:].startswith(rc[:len(s1.sequence)-i]): return True return False
Пример:
a = Strand("ATGCGT") b = Strand("ACGCAT") print(can_hybridize(a, b)) # True
Здесь мы проверяем: может ли вторая цепь при перевороте и комплементации хотя бы частично приклеиться к первой.
3. ПЦР: полимеразная цепная реакция
ПЦР — это способ быстро наращивать миллионы копий ДНК с помощью фермента и температурных циклов.
from random import randint def pcr_amplify(template: Strand, primers: List[Strand], cycles: int = 30) -> List[Strand]: amplified = [] for _ in range(cycles): for primer in primers: if primer.sequence in template.sequence: start = template.sequence.find(primer.sequence) amplified.append(Strand(template.sequence[start:])) return amplified template = Strand("ATGCGTACCGTTAAGT") primer1 = Strand("ATGCG") primer2 = Strand("AAGT") products = pcr_amplify(template, [primer1, primer2]) print(f"Products: {len(products)}")
Это упрощённая модель, но она демонстрирует суть: каждый цикл удваивает фрагменты, на которые садятся праймеры.
4. Лигирование: склеивание фрагментов
Фермент лигаза соединяет два фрагмента ДНК, если они совместимы (например, если один заканчивается на последовательность, с которой начинается другой).
def ligate(s1: Strand, s2: Strand) -> Strand: # простое сшивание, без проверки комплементарности return Strand(s1.sequence + s2.sequence) frag1 = Strand("ATGCGT") frag2 = Strand("ACCGTA") ligated = ligate(frag1, frag2) print(ligated) # 5'-ATGCGTACCGTA-3'
В реальности нужна проверка на “липкие концы” (sticky ends). Но даже простая конкатенация уже позволяет моделировать базовое склеивание.
5. Ошибки и мутации
Биология не бывает идеальной. Мутации — часть игры.
from random import choice, random def mutate(s: Strand, rate: float = 0.01) -> Strand: new_seq = "" for base in s.sequence: if random() < rate: new_seq += choice("ATCG".replace(base, "")) else: new_seq += base return Strand(new_seq) original = Strand("ATGCGTACCGTTAAGT") mutated = mutate(original, rate=0.1) print(f"Original: {original}") print(f"Mutated : {mutated}")
С мутациями можно играть: вставки, делеции, инверсии, перестройки. Особенно забавно смотреть, как они влияют на “виртуальный геном”.
6. Построим плазмиду
Соберём кольцевую ДНК, как это делают в лабораториях. В простом случае представим кольцо как фрагмент, где 3′-конец соединяется с 5′-концом.
class Plasmid(Strand): def __repr__(self): return f"Circular 5'-{self.sequence}-3'" def cut(self, site: str) -> List[Strand]: if site not in self.sequence: return [self] idx = self.sequence.find(site) return [Strand(self.sequence[:idx]), Strand(self.sequence[idx:])] plasmid = Plasmid("ATGCGTACCGTTAAGTCCGATC") cut_fragments = plasmid.cut("CCGTTA") for f in cut_fragments: print(f)
Теперь мы можем разрезать плазмиды, вставлять гены и даже симулировать клонирование.
Заключение
Всё вышеприведённое — это даже не поверхность. Это царапина на внешнем слое синтетической биологии. Можно углубляться в:
-
Моделирование температурных профилей (анализ работы ПЦР при разных температурах).
-
Ферментативную кинетику (микроскопично эмулировать скорость работы ДНК-полимеразы).
-
Химию буферов (учёт pH, концентрации ионов взаимодействия).
-
Вероятность отжига праймеров (точное моделирование Tm).
И это будет только интереснее.
Главный вывод: биология прекрасно ложится на программирование. Более того, если вы программист — вы уже почти синтетический биолог. Вам просто нужно немного других библиотек… и чуть больше пипеток.
А пока можно собрать собственный геном, сшить его из фрагментов и “запустить” in silico.
P.S. Кода здесь много, но вы можете легко собрать из него полноценную симуляцию. Попробуйте, например, реализовать CRISPR. Или хотя бы фермент EcoRI.
Если нужен Jupyter Notebook с полным примером — напишите в комментариях, подготовим.
ссылка на оригинал статьи https://habr.com/ru/articles/916192/
Добавить комментарий