diff --git a/hw2_decor_iter/HW_2.ipynb b/hw2_decor_iter/HW_2.ipynb new file mode 100644 index 0000000..580d343 --- /dev/null +++ b/hw2_decor_iter/HW_2.ipynb @@ -0,0 +1,657 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "72f5013c-f4b9-4a1f-aed9-7e47623e7c8a", + "metadata": {}, + "source": [ + "# Задание 1 (2 балла)" + ] + }, + { + "cell_type": "markdown", + "id": "0e818fc0-4716-45c6-8942-7b60da358200", + "metadata": {}, + "source": [ + "Напишите класс `MyDict`, который будет полностью повторять поведение обычного словаря, за исключением того, что при итерации мы должны получать и ключи, и значения.\n", + "\n", + "**Модули использовать нельзя**" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "3dc27675-99fc-4040-a8f7-aa20be51c816", + "metadata": {}, + "outputs": [], + "source": [ + "class MyDict(dict):\n", + " def __iter__(self):\n", + " return zip(self.keys(), self.values())" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "7d9ab39d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'a': 1, 'b': 2, 'c': 3, 'd': 25}" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dct = MyDict({\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 25})\n", + "dct" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "c8a37242", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('a', 1)\n", + "('b', 2)\n", + "('c', 3)\n", + "('d', 25)\n" + ] + } + ], + "source": [ + "for item in iter(dct):\n", + " print(item)" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "a96e453e-2553-40b1-889f-cce04c6db771", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a 1\n", + "b 2\n", + "c 3\n", + "d 25\n" + ] + } + ], + "source": [ + "for key, value in dct:\n", + " print(key, value) " + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "d3b93507-d88a-4773-8d6f-31990e1effbc", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a 1\n", + "b 2\n", + "c 3\n", + "d 25\n" + ] + } + ], + "source": [ + "for key, value in dct.items():\n", + " print(key, value)" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "9be2de18-f963-4de0-afba-c183a9a56087", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "b\n", + "c\n", + "d\n" + ] + } + ], + "source": [ + "for key in dct.keys():\n", + " print(key)" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "b7bfbf08-7253-4aab-a9a0-a8e8500c5a29", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "28" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "dct[\"c\"] + dct[\"d\"]" + ] + }, + { + "cell_type": "markdown", + "id": "4bde5544-afd0-408e-a03b-dad5096ee685", + "metadata": {}, + "source": [ + "# Задание 2 (2 балла)" + ] + }, + { + "cell_type": "markdown", + "id": "36e85085-9990-4a2a-a005-f5ef3afd438d", + "metadata": {}, + "source": [ + "Напишите функцию `iter_append`, которая \"добавляет\" новый элемент в конец итератора, возвращая итератор, который включает изначальные элементы и новый элемент. Итерироваться по итератору внутри функции нельзя, то есть вот такая штука не принимается\n", + "```python\n", + "def iter_append(iterator, item):\n", + " lst = list(iterator) + [item]\n", + " return iter(lst)\n", + "```\n", + "\n", + "**Модули использовать нельзя**" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "id": "d1ecef6f", + "metadata": {}, + "outputs": [], + "source": [ + "def iter_append(iterator, item):\n", + " new_iterator = []\n", + " while True:\n", + " try:\n", + " elem = next(iterator)\n", + " new_iterator.append(elem)\n", + " except StopIteration:\n", + " new_iterator.append(item)\n", + " break\n", + " return new_iterator" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "02013430", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "my_iterator = iter([1, 2, 3])\n", + "new_iterator = iter_append(my_iterator, 4)\n", + "\n", + "for element in new_iterator:\n", + " print(element)" + ] + }, + { + "cell_type": "markdown", + "id": "72c35894-0caf-41ac-a584-56058b243f29", + "metadata": {}, + "source": [ + "# Задание 3 (5 баллов)" + ] + }, + { + "cell_type": "markdown", + "id": "884be4ed-b388-4b36-ad7d-d6835a87425e", + "metadata": {}, + "source": [ + "Представим, что мы установили себе некотoрую библиотеку, которая содержит в себе два класса `MyString` и `MySet`, которые являются наследниками `str` и `set`, но также несут и дополнительные методы.\n", + "\n", + "Проблема заключается в том, что библиотеку писали не очень аккуратные люди, поэтому получилось так, что некоторые методы возвращают не тот тип данных, который мы ожидаем. Например, `MyString().reverse()` возвращает объект класса `str`, хотя логичнее было бы ожидать объект класса `MyString`.\n", + "\n", + "Найдите и реализуйте удобный способ сделать так, чтобы подобные методы возвращали экземпляр текущего класса, а не родительского. При этом **код методов изменять нельзя**\n", + "\n", + "**+3 дополнительных балла** за реализацию того, чтобы **унаследованные от `str` и `set` методы** также возвращали объект интересующего нас класса (то есть `MyString.replace(..., ...)` должен возвращать `MyString`). **Переопределять методы нельзя**\n", + "\n", + "**Модули использовать нельзя**" + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "id": "7973388e-c16f-437f-a1af-30ddd69f7671", + "metadata": {}, + "outputs": [], + "source": [ + "def wrapper_MyString(func):\n", + " def inner_func(input_str):\n", + " result_str = func(input_str)\n", + " result_MyString = MyString(result_str)\n", + " return result_MyString\n", + " return inner_func\n", + "\n", + "\n", + "def wrapper_MySet(func):\n", + " def inner_func(*args):\n", + " result_set = func(*args)\n", + " result_MySet = MySet(result_set)\n", + " return result_MySet\n", + " return inner_func\n", + " \n", + "\n", + " \n", + "\n", + "class MyString(str):\n", + " @wrapper_MyString\n", + " def reverse(self):\n", + " return self[::-1]\n", + " \n", + " @wrapper_MyString\n", + " def make_uppercase(self):\n", + " return \"\".join([chr(ord(char) - 32) if 97 <= ord(char) <= 122 else char for char in self])\n", + "\n", + " @wrapper_MyString\n", + " def make_lowercase(self):\n", + " return \"\".join([chr(ord(char) + 32) if 65 <= ord(char) <= 90 else char for char in self])\n", + " \n", + " @wrapper_MyString\n", + " def capitalize_words(self):\n", + " return \" \".join([word.capitalize() for word in self.split()])\n", + " \n", + " \n", + "class MySet(set):\n", + " def is_empty(self):\n", + " return len(self) == 0\n", + " \n", + " def has_duplicates(self):\n", + " return len(self) != len(set(self))\n", + " \n", + " @wrapper_MySet\n", + " def union_with(self, other):\n", + " return self.union(other)\n", + " \n", + " @wrapper_MySet\n", + " def intersection_with(self, other):\n", + " return self.intersection(other)\n", + " \n", + " @wrapper_MySet\n", + " def difference_with(self, other):\n", + " return self.difference(other)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "8b985a7b-ddf2-47ce-8b76-a4dd921a2e06", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "string_example = MyString(\"Aa Bb Cc\")\n", + "set_example_1 = MySet({1, 2, 3, 4})\n", + "set_example_2 = MySet({3, 4, 5, 6, 6})\n", + "\n", + "print(type(string_example.reverse()))\n", + "print(type(string_example.make_uppercase()))\n", + "print(type(string_example.make_lowercase()))\n", + "print(type(string_example.capitalize_words()))\n", + "print()\n", + "print(type(set_example_1.is_empty()))\n", + "print(type(set_example_2.has_duplicates()))\n", + "print(type(set_example_1.union_with(set_example_2)))\n", + "print(type(set_example_1.difference_with(set_example_2)))" + ] + }, + { + "cell_type": "markdown", + "id": "f246ecea-9aaa-45c6-98e4-996dc9cdce14", + "metadata": {}, + "source": [ + "# Задание 4 (5 баллов)" + ] + }, + { + "cell_type": "markdown", + "id": "e66831d7-df9c-4778-9942-bbb8796fef1e", + "metadata": {}, + "source": [ + "Напишите декоратор `switch_privacy`:\n", + "1. Делает все публичные **методы** класса приватными\n", + "2. Делает все приватные методы класса публичными\n", + "3. Dunder методы и защищённые методы остаются без изменений\n", + "4. Должен работать тестовый код ниже, в теле класса писать код нельзя\n", + "\n", + "**Модули использовать нельзя**" + ] + }, + { + "cell_type": "code", + "execution_count": 112, + "id": "733db8d6-87b8-4797-97be-d3b901422ded", + "metadata": {}, + "outputs": [], + "source": [ + "# Ваш код здесь\n", + "class ExampleClass:\n", + " # Но не здесь\n", + " def public_method(self):\n", + " return 1\n", + " \n", + " def _protected_method(self):\n", + " return 2\n", + " \n", + " def __private_method(self):\n", + " return 3\n", + " \n", + " def __dunder_method__(self):\n", + " pass" + ] + }, + { + "cell_type": "code", + "execution_count": 113, + "id": "c936077d-e618-459c-bbcc-6ad1b22d0975", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 113, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_object = ExampleClass()\n", + "\n", + "test_object._ExampleClass__public_method() # Публичный метод стал приватным" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "id": "10603672-80cf-460c-9305-d0950094419d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 114, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_object.private_method() # Приватный метод стал публичным" + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "id": "f30b1ef8-0f80-482d-89f1-09caece61c88", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 115, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_object._protected_method() # Защищённый метод остался защищённым" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "id": "71d51e6e-62b5-4440-af3e-75088761b1bf", + "metadata": {}, + "outputs": [], + "source": [ + "test_object.__dunder_method__() # Дандер метод не изменился" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "id": "a97cf0c4-4881-441c-83b6-ef8955377585", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(False, False)" + ] + }, + "execution_count": 117, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hasattr(test_object, \"public_method\"), hasattr(test_object, \"private\") # Изначальные варианты изменённых методов не сохраняются" + ] + }, + { + "cell_type": "markdown", + "id": "31ad0bdd-9a24-4d6c-a499-e975b4b6acdd", + "metadata": {}, + "source": [ + "# Задание 5 (7 баллов)" + ] + }, + { + "cell_type": "markdown", + "id": "68c75d25-37f7-491d-bcc0-ba74e8bdb364", + "metadata": {}, + "source": [ + "Напишите [контекстный менеджер](https://docs.python.org/3/library/stdtypes.html#context-manager-types) `OpenFasta`\n", + "\n", + "Контекстные менеджеры это специальные объекты, которые могут работать с конструкцией `with ... as ...:`. В них нет ничего сложного, для их реализации как обычно нужно только определить только пару dunder методов. Изучите этот вопрос самостоятельно\n", + "\n", + "1. Объект должен работать как обычные файлы в питоне (наследоваться не надо, здесь лучше будет использовать **композицию**), но:\n", + " + При итерации по объекту мы должны будем получать не строку из файла, а специальный объект `FastaRecord`. Он будет хранить в себе информацию о последовательности. Важно, **не строки, а именно последовательности**, в fasta файлах последовательность часто разбивают на много строк\n", + " + Нужно написать методы `read_record` и `read_records`, которые по смыслу соответствуют `readline()` и `readlines()` в обычных файлах, но они должны выдавать не строки, а объект(ы) `FastaRecord`\n", + "2. Конструктор должен принимать один аргумент - **путь к файлу**\n", + "3. Класс должен эффективно распоряжаться памятью, с расчётом на работу с очень большими файлами\n", + " \n", + "Объект `FastaRecord`. Это должен быть **датакласс** (см. про примеры декораторов в соответствующей лекции) с тремя полями:\n", + "+ `seq` - последовательность\n", + "+ `id_` - ID последовательности (это то, что в фаста файле в строке, которая начинается с `>` до первого пробела. Например, >**GTD326487.1** Species anonymous 24 chromosome) \n", + "+ `description` - то, что осталось после ID (Например, >GTD326487.1 **Species anonymous 24 chromosome**)\n", + "\n", + "\n", + "Напишите демонстрацию работы кода с использованием всех написанных методов, обязательно добавьте файл с тестовыми данными в репозиторий (не обязательно большой)\n", + "\n", + "**Можно использовать модули из стандартной библиотеки**" + ] + }, + { + "cell_type": "code", + "execution_count": 153, + "id": "5188b5d5-1e6e-4b11-9b54-9ba809210dfc", + "metadata": {}, + "outputs": [], + "source": [ + "# Ваш код здесь\n", + "\n", + "\n", + "with OpenFasta(os.path.join(\"data\", \"example.fasta\")) as fasta:\n", + " # Ваш код здесь\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "id": "4db652e9-7697-4dd7-bcc3-649bdc18c1c4", + "metadata": {}, + "source": [ + "# Задание 6 (7 баллов)" + ] + }, + { + "cell_type": "markdown", + "id": "a8ba05f3-29f0-48be-a477-c1f61a9e0537", + "metadata": {}, + "source": [ + "1. Напишите код, который позволит получать все возможные (неуникальные) генотипы при скрещивании двух организмов. Это может быть функция или класс, что вам кажется более удобным.\n", + "\n", + "Например, все возможные исходы скрещивания \"Aabb\" и \"Aabb\" (неуникальные) это\n", + "\n", + "```\n", + "AAbb\n", + "AAbb\n", + "AAbb\n", + "AAbb\n", + "Aabb\n", + "Aabb\n", + "Aabb\n", + "Aabb\n", + "Aabb\n", + "Aabb\n", + "Aabb\n", + "Aabb\n", + "aabb\n", + "aabb\n", + "aabb\n", + "aabb\n", + "```\n", + "\n", + "2. Напишите функцию, которая вычисляет вероятность появления определённого генотипа (его ожидаемую долю в потомстве).\n", + "Например,\n", + "\n", + "```python\n", + "get_offspting_genotype_probability(parent1=\"Aabb\", parent2=\"Aabb\", target_genotype=\"Аabb\") # 0.5\n", + "\n", + "```\n", + "\n", + "3. Напишите код, который выводит все уникальные генотипы при скрещивании `'АаБбввГгДдЕеЖжЗзИиЙйккЛлМмНн'` и `'АаббВвГгДДЕеЖжЗзИиЙйКкЛлМмНН'`, которые содержат в себе следующую комбинацию аллелей `'АаБбВвГгДдЕеЖжЗзИиЙйКкЛл'`\n", + "4. Напишите код, который расчитывает вероятность появления генотипа `'АаБбввГгДдЕеЖжЗзИиЙйккЛлМмНн'` при скрещивании `АаБбВвГгДдЕеЖжЗзИиЙйКкЛлМмНн` и `АаБбВвГгДдЕеЖжЗзИиЙйКкЛлМмНн`\n", + "\n", + "Важные замечания:\n", + "1. Порядок следования аллелей в случае гетерозигот всегда должен быть следующим: сначала большая буква, затем маленькая (вариант `AaBb` допустим, но `aAbB` быть не должно)\n", + "2. Подзадачи 3 и 4 могут потребовать много вычислительного времени (до 15+ минут в зависимости от железа), поэтому убедитесь, что вы хорошо протестировали написанный вами код на малых данных перед выполнением этих задач. Если ваш код работает **дольше 20 мин**, то скорее всего ваше решение не оптимально, попытайтесь что-нибудь оптимизировать. Если оптимальное решение совсем не получается, то попробуйте из входных данных во всех заданиях убрать последний ген (это должно уменьшить время выполнения примерно в 4 раза), но **за такое решение будет снято 2 балла**\n", + "3. Несмотря на то, что подзадания 2, 3 и 4 возможно решить математически, не прибегая к непосредственному получению всех возможных генотипов, от вас требуется именно brute-force вариант алгоритма\n", + "\n", + "**Можно использовать модули из стандартной библиотеки питона**, но **за выполнение задания без использования модулей придусмотрено +3 дополнительных балла**" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "c64841e9-dfcd-45bb-bcaa-d672ea03a744", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Ваш код здесь (1 и 2 подзадание)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "fdfb6d8c-0da7-4857-9579-6921dc409eb3", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# Ваш код здесь (3 подзадание)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "3e8a17cc-0642-49ae-ba6b-51ab5499660e", + "metadata": {}, + "outputs": [], + "source": [ + "# Ваш код здесь (4 подзадание)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/hw2_decor_iter/HW_2.py b/hw2_decor_iter/HW_2.py new file mode 100644 index 0000000..1b2b37d --- /dev/null +++ b/hw2_decor_iter/HW_2.py @@ -0,0 +1,337 @@ +#!/usr/bin/env python +# coding: utf-8 + +# # Задание 1 (2 балла) + +# Напишите класс `MyDict`, который будет полностью повторять поведение обычного словаря, за исключением того, что при итерации мы должны получать и ключи, и значения. +# +# **Модули использовать нельзя** + +# In[22]: + + +class MyDict(dict): + def __iter__(self): + return zip(self.keys(), self.values()) + + +# In[23]: + + +dct = MyDict({"a": 1, "b": 2, "c": 3, "d": 25}) +dct + + +# In[33]: + + +for item in iter(dct): + print(item) + + +# In[29]: + + +for key, value in dct: + print(key, value) + + +# In[30]: + + +for key, value in dct.items(): + print(key, value) + + +# In[31]: + + +for key in dct.keys(): + print(key) + + +# In[32]: + + +dct["c"] + dct["d"] + + +# # Задание 2 (2 балла) + +# Напишите функцию `iter_append`, которая "добавляет" новый элемент в конец итератора, возвращая итератор, который включает изначальные элементы и новый элемент. Итерироваться по итератору внутри функции нельзя, то есть вот такая штука не принимается +# ```python +# def iter_append(iterator, item): +# lst = list(iterator) + [item] +# return iter(lst) +# ``` +# +# **Модули использовать нельзя** + +# In[58]: + + +def iter_append(iterator, item): + new_iterator = [] + while True: + try: + elem = next(iterator) + new_iterator.append(elem) + except StopIteration: + new_iterator.append(item) + break + return new_iterator + + +# In[59]: + + +my_iterator = iter([1, 2, 3]) +new_iterator = iter_append(my_iterator, 4) + +for element in new_iterator: + print(element) + + +# # Задание 3 (5 баллов) + +# Представим, что мы установили себе некотoрую библиотеку, которая содержит в себе два класса `MyString` и `MySet`, которые являются наследниками `str` и `set`, но также несут и дополнительные методы. +# +# Проблема заключается в том, что библиотеку писали не очень аккуратные люди, поэтому получилось так, что некоторые методы возвращают не тот тип данных, который мы ожидаем. Например, `MyString().reverse()` возвращает объект класса `str`, хотя логичнее было бы ожидать объект класса `MyString`. +# +# Найдите и реализуйте удобный способ сделать так, чтобы подобные методы возвращали экземпляр текущего класса, а не родительского. При этом **код методов изменять нельзя** +# +# **+3 дополнительных балла** за реализацию того, чтобы **унаследованные от `str` и `set` методы** также возвращали объект интересующего нас класса (то есть `MyString.replace(..., ...)` должен возвращать `MyString`). **Переопределять методы нельзя** +# +# **Модули использовать нельзя** + +# In[115]: + + +def wrapper_MyString(func): + def inner_func(input_str): + result_str = func(input_str) + result_MyString = MyString(result_str) + return result_MyString + return inner_func + + +def wrapper_MySet(func): + def inner_func(*args): + result_set = func(*args) + result_MySet = MySet(result_set) + return result_MySet + return inner_func + + + + +class MyString(str): + @wrapper_MyString + def reverse(self): + return self[::-1] + + @wrapper_MyString + def make_uppercase(self): + return "".join([chr(ord(char) - 32) if 97 <= ord(char) <= 122 else char for char in self]) + + @wrapper_MyString + def make_lowercase(self): + return "".join([chr(ord(char) + 32) if 65 <= ord(char) <= 90 else char for char in self]) + + @wrapper_MyString + def capitalize_words(self): + return " ".join([word.capitalize() for word in self.split()]) + + +class MySet(set): + def is_empty(self): + return len(self) == 0 + + def has_duplicates(self): + return len(self) != len(set(self)) + + @wrapper_MySet + def union_with(self, other): + return self.union(other) + + @wrapper_MySet + def intersection_with(self, other): + return self.intersection(other) + + @wrapper_MySet + def difference_with(self, other): + return self.difference(other) + + +# In[26]: + + +string_example = MyString("Aa Bb Cc") +set_example_1 = MySet({1, 2, 3, 4}) +set_example_2 = MySet({3, 4, 5, 6, 6}) + +print(type(string_example.reverse())) +print(type(string_example.make_uppercase())) +print(type(string_example.make_lowercase())) +print(type(string_example.capitalize_words())) +print() +print(type(set_example_1.is_empty())) +print(type(set_example_2.has_duplicates())) +print(type(set_example_1.union_with(set_example_2))) +print(type(set_example_1.difference_with(set_example_2))) + + +# # Задание 4 (5 баллов) + +# Напишите декоратор `switch_privacy`: +# 1. Делает все публичные **методы** класса приватными +# 2. Делает все приватные методы класса публичными +# 3. Dunder методы и защищённые методы остаются без изменений +# 4. Должен работать тестовый код ниже, в теле класса писать код нельзя +# +# **Модули использовать нельзя** + +# In[112]: + + +# Ваш код здесь +class ExampleClass: + # Но не здесь + def public_method(self): + return 1 + + def _protected_method(self): + return 2 + + def __private_method(self): + return 3 + + def __dunder_method__(self): + pass + + +# In[113]: + + +test_object = ExampleClass() + +test_object._ExampleClass__public_method() # Публичный метод стал приватным + + +# In[114]: + + +test_object.private_method() # Приватный метод стал публичным + + +# In[115]: + + +test_object._protected_method() # Защищённый метод остался защищённым + + +# In[116]: + + +test_object.__dunder_method__() # Дандер метод не изменился + + +# In[117]: + + +hasattr(test_object, "public_method"), hasattr(test_object, "private") # Изначальные варианты изменённых методов не сохраняются + + +# # Задание 5 (7 баллов) + +# Напишите [контекстный менеджер](https://docs.python.org/3/library/stdtypes.html#context-manager-types) `OpenFasta` +# +# Контекстные менеджеры это специальные объекты, которые могут работать с конструкцией `with ... as ...:`. В них нет ничего сложного, для их реализации как обычно нужно только определить только пару dunder методов. Изучите этот вопрос самостоятельно +# +# 1. Объект должен работать как обычные файлы в питоне (наследоваться не надо, здесь лучше будет использовать **композицию**), но: +# + При итерации по объекту мы должны будем получать не строку из файла, а специальный объект `FastaRecord`. Он будет хранить в себе информацию о последовательности. Важно, **не строки, а именно последовательности**, в fasta файлах последовательность часто разбивают на много строк +# + Нужно написать методы `read_record` и `read_records`, которые по смыслу соответствуют `readline()` и `readlines()` в обычных файлах, но они должны выдавать не строки, а объект(ы) `FastaRecord` +# 2. Конструктор должен принимать один аргумент - **путь к файлу** +# 3. Класс должен эффективно распоряжаться памятью, с расчётом на работу с очень большими файлами +# +# Объект `FastaRecord`. Это должен быть **датакласс** (см. про примеры декораторов в соответствующей лекции) с тремя полями: +# + `seq` - последовательность +# + `id_` - ID последовательности (это то, что в фаста файле в строке, которая начинается с `>` до первого пробела. Например, >**GTD326487.1** Species anonymous 24 chromosome) +# + `description` - то, что осталось после ID (Например, >GTD326487.1 **Species anonymous 24 chromosome**) +# +# +# Напишите демонстрацию работы кода с использованием всех написанных методов, обязательно добавьте файл с тестовыми данными в репозиторий (не обязательно большой) +# +# **Можно использовать модули из стандартной библиотеки** + +# In[153]: + + +# Ваш код здесь + + +with OpenFasta(os.path.join("data", "example.fasta")) as fasta: + # Ваш код здесь + pass + + +# # Задание 6 (7 баллов) + +# 1. Напишите код, который позволит получать все возможные (неуникальные) генотипы при скрещивании двух организмов. Это может быть функция или класс, что вам кажется более удобным. +# +# Например, все возможные исходы скрещивания "Aabb" и "Aabb" (неуникальные) это +# +# ``` +# AAbb +# AAbb +# AAbb +# AAbb +# Aabb +# Aabb +# Aabb +# Aabb +# Aabb +# Aabb +# Aabb +# Aabb +# aabb +# aabb +# aabb +# aabb +# ``` +# +# 2. Напишите функцию, которая вычисляет вероятность появления определённого генотипа (его ожидаемую долю в потомстве). +# Например, +# +# ```python +# get_offspting_genotype_probability(parent1="Aabb", parent2="Aabb", target_genotype="Аabb") # 0.5 +# +# ``` +# +# 3. Напишите код, который выводит все уникальные генотипы при скрещивании `'АаБбввГгДдЕеЖжЗзИиЙйккЛлМмНн'` и `'АаббВвГгДДЕеЖжЗзИиЙйКкЛлМмНН'`, которые содержат в себе следующую комбинацию аллелей `'АаБбВвГгДдЕеЖжЗзИиЙйКкЛл'` +# 4. Напишите код, который расчитывает вероятность появления генотипа `'АаБбввГгДдЕеЖжЗзИиЙйккЛлМмНн'` при скрещивании `АаБбВвГгДдЕеЖжЗзИиЙйКкЛлМмНн` и `АаБбВвГгДдЕеЖжЗзИиЙйКкЛлМмНн` +# +# Важные замечания: +# 1. Порядок следования аллелей в случае гетерозигот всегда должен быть следующим: сначала большая буква, затем маленькая (вариант `AaBb` допустим, но `aAbB` быть не должно) +# 2. Подзадачи 3 и 4 могут потребовать много вычислительного времени (до 15+ минут в зависимости от железа), поэтому убедитесь, что вы хорошо протестировали написанный вами код на малых данных перед выполнением этих задач. Если ваш код работает **дольше 20 мин**, то скорее всего ваше решение не оптимально, попытайтесь что-нибудь оптимизировать. Если оптимальное решение совсем не получается, то попробуйте из входных данных во всех заданиях убрать последний ген (это должно уменьшить время выполнения примерно в 4 раза), но **за такое решение будет снято 2 балла** +# 3. Несмотря на то, что подзадания 2, 3 и 4 возможно решить математически, не прибегая к непосредственному получению всех возможных генотипов, от вас требуется именно brute-force вариант алгоритма +# +# **Можно использовать модули из стандартной библиотеки питона**, но **за выполнение задания без использования модулей придусмотрено +3 дополнительных балла** + +# In[18]: + + +# Ваш код здесь (1 и 2 подзадание) + + +# In[20]: + + +# Ваш код здесь (3 подзадание) + + +# In[21]: + + +# Ваш код здесь (4 подзадание) +