From 593c7ef92ded7f535ae2f7881dd09185722e8415 Mon Sep 17 00:00:00 2001 From: pibragimov Date: Sun, 1 Oct 2023 23:00:11 +0300 Subject: [PATCH] feat: add lecture --- chapter-3/example.db | Bin 0 -> 8192 bytes chapter-3/example.txt | 1 + chapter-3/lecture.ipynb | 970 +++++++++++++++++++++++++++------------- 3 files changed, 671 insertions(+), 300 deletions(-) create mode 100644 chapter-3/example.db create mode 100644 chapter-3/example.txt diff --git a/chapter-3/example.db b/chapter-3/example.db new file mode 100644 index 0000000000000000000000000000000000000000..2e00bede35f96ac45331a8f2c4510861d0a72105 GIT binary patch literal 8192 zcmeI#v1$TA5C-7cyEBC%n?@{xFl7X>@ddnuB}!D{WeY7=T;b$YFl!zy&tPfe1NZ`Y zfK=`lqFqv^_:\n", - " <поля и методы класса>\n", - "```" + "# Занятие 3. Итераторы, генераторы и context manager\n" ] }, { - "cell_type": "code", - "execution_count": 1, - "id": "distant-reminder", + "cell_type": "markdown", + "id": "e8432131-06d0-4f09-bf78-126e7f3a7883", + "metadata": {}, + "source": [ + "## Декораторы" + ] + }, + { + "cell_type": "markdown", + "id": "cba08bf8-9ece-4044-8e11-7c265c14ab00", + "metadata": {}, + "source": [ + "Декоратор — это объект, который расширяет возможности функции, не меняя её исходный кода." + ] + }, + { + "cell_type": "markdown", + "id": "e7fc460d-6909-4e85-a6d0-df138836f561", "metadata": {}, - "outputs": [], "source": [ - "class A:\n", - " pass" + "Принцип работы декоратора:\n", + "1. принимает функцию как аргумент\n", + "2. объявляет новую функцию, которая расширяет функцию-аргумент\n", + "3. возвращает новую функцию в качестве объекта.\n" ] }, { "cell_type": "code", - "execution_count": 2, - "id": "authorized-nutrition", + "execution_count": 105, + "id": "74672e8f-586f-473b-86fc-f6fe1568db45", "metadata": {}, "outputs": [], "source": [ - "a = A()" + "from typing import Callable, Any\n", + "\n", + "\n", + "def counter(f: Callable[[Any], Any]) -> Callable[[Any], Any]:\n", + " count = 0\n", + "\n", + " # Объявляем функцию, которая расширяет функционал f\n", + " def decorated(*args: Any, **kwargs: Any) -> Any:\n", + " # Переменная total объявлена нелокальной для доступа из внутренней функции\n", + " # Такой подход называется \"замыкание\"\n", + " nonlocal count\n", + " count += 1\n", + " print(f\"Called function {f} {count} times\")\n", + "\n", + " return f(*args, **kwargs)\n", + "\n", + " # Возвращаем новую функцию как объект\n", + " return decorated\n", + "\n", + "\n", + "@counter\n", + "def hello(name: str) -> str:\n", + " return f\"Привет, {name}!\"" ] }, { "cell_type": "code", - "execution_count": 6, - "id": "welcome-recommendation", + "execution_count": 121, + "id": "c8f808e6-b9e7-493c-9675-2d9fa5c9dc8e", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Called function 16 times\n" + ] + }, { "data": { "text/plain": [ - "(float, True)" + "'Привет, Студент_1!'" ] }, - "execution_count": 6, + "execution_count": 121, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# type - возвращает тип\n", - "# isinstance(x, y) возвращает True если x принадлежит классу y\n", - "type(1.0), isinstance(\"a\", str)" + "hello(\"Студент_1\")" ] }, { "cell_type": "code", - "execution_count": 22, - "id": "moderate-measure", + "execution_count": 152, + "id": "9a7c6169-79d6-47d3-a3ca-445f97b9d397", "metadata": {}, "outputs": [], "source": [ - "class Student:\n", - " # __init__ - метод инициализации объекта\n", - " def __init__(self, name, age=18):\n", - " self.name = name\n", - " self.age = age\n", + "import time\n", + "from typing import Callable, Any\n", + "import random\n", "\n", - " self.group = \"itam_python_courses\"\n", "\n", - " def return_age(self):\n", - " return self.age" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "id": "seeing-assessment", - "metadata": {}, - "outputs": [], - "source": [ - "artem = Student(\"artem\", 25)\n", - "ivan = Student(\"ivan_xxx\", 0)" + "def timer(f: Callable[[Any], Any]):\n", + " # Объявляем функцию, которая расширяет функционал f\n", + " def decorated(*args: Any, **kwargs: Any) -> Any:\n", + " # Переменная total объявлена нелокальной для доступа из внутренней функции\n", + " t0 = time.monotonic()\n", + " # Возвращаем значение исходной функции и дополнительно total\n", + " result = f(*args, **kwargs)\n", + "\n", + " print(f\"Called function {f} in {time.monotonic() - t0:.2f}s\")\n", + " return result\n", + "\n", + " # Возвращаем новую функцию как объект\n", + " return decorated\n", + "\n", + "\n", + "@timer\n", + "def hello(name: str) -> str:\n", + " time.sleep(random.randint(0, 10) / 100)\n", + " return f\"Привет, {name}!\"" ] }, { "cell_type": "code", - "execution_count": 35, - "id": "musical-cycle", + "execution_count": 151, + "id": "7942ea39-39b6-47fe-8f3f-87857268f4b7", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Called function in 0.10s\n", + "Привет, Студент_1!\n" + ] + } + ], "source": [ - "class Student:\n", - " # данное поле - статическое\n", - " # статическое поле - доступное через имя класса\n", - " _count_students = 0\n", - "\n", - " def __init__(self, name, age=18):\n", - " self.name = name\n", - " self.age = age\n", - " Student._count_students += 1\n", - "\n", - " # @staticmethod - делает метод статическим\n", - " @staticmethod\n", - " def amount():\n", - " return Student._count_students" + "print(hello(\"Студент_1\"))" ] }, { - "cell_type": "code", - "execution_count": 53, - "id": "surface-provision", + "cell_type": "markdown", + "id": "d6dd6d20-1d39-4fe8-a41b-9b183da3fc9c", "metadata": {}, - "outputs": [], "source": [ - "a, b, c = Student(\"peter\"), Student(\"seva\"), Student(\"michael\")" + "### Фабрика декораторов" ] }, { "cell_type": "code", - "execution_count": 60, - "id": "seeing-norwegian", + "execution_count": 63, + "id": "a7556f98-a280-47cd-a8df-379f5155edd6", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "14" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "result is Привет, Студент_418!\n", + "num of loops is 3\n", + "avg time elapsed 0.603494527672107\n" + ] } ], "source": [ - "Student.amount()" + "from time import perf_counter, sleep\n", + "import random\n", + "from typing import Callable, Any\n", + "\n", + "\n", + "def decorator_factory(loops_num: int):\n", + " def decorating(f: Callable[[Any], Any]):\n", + " def inner(*args, **kwargs):\n", + " total_elapsed = 0\n", + " for i in range(loops_num):\n", + " start = perf_counter()\n", + " result = f(*args, **kwargs)\n", + " end = perf_counter()\n", + " total_elapsed += end - start\n", + " avg_run_time = total_elapsed / loops_num\n", + " print(\"result is\", result)\n", + " print(\"num of loops is\", loops_num)\n", + " print(\"avg time elapsed\", avg_run_time)\n", + "\n", + " return inner\n", + "\n", + " return decorating\n", + "\n", + "\n", + "@decorator_factory(3)\n", + "def hello(name):\n", + " sleep(random.random())\n", + " return f\"Привет, {name}!\"\n", + "\n", + "\n", + "hello(\"Студент_418\")" ] }, { "cell_type": "code", - "execution_count": 62, - "id": "talented-speaking", + "execution_count": 64, + "id": "1e3385a8-e4e5-4142-a402-570161c858dd", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "result is Привет, Студент_418!\n", + "num of loops is 3\n", + "avg time elapsed 0.46702827761570614\n" + ] + } + ], "source": [ - "class Student:\n", - " _count_students = 0\n", + "class Decorator_Factory_Class:\n", + " def __init__(self, num_loops):\n", + " self.num_loops = num_loops\n", + "\n", + " def __call__(self, fn):\n", + " def inner(num):\n", + " total_elapsed = 0\n", + " for i in range(self.num_loops):\n", + " start = perf_counter()\n", + " result = fn(num)\n", + " end = perf_counter()\n", + " total_elapsed += end - start\n", + " avg_run_time = total_elapsed / self.num_loops\n", + " print(\"num of loops is\", self.num_loops)\n", + " return result\n", + "\n", + " return inner\n", "\n", - " def __init__(self, name, age=18):\n", - " self.name = name\n", - " self.age = age\n", - " Student._count_students += 1\n", "\n", - " # Через self можно обращаться к полям объекта\n", - " def return_data(self):\n", - " return self.name + \", \" + str(self.age)" + "@decorator_factory(3)\n", + "def hello(name):\n", + " sleep(random.random())\n", + " return f\"Привет, {name}!\"\n", + "\n", + "\n", + "hello(\"Студент_418\")" ] }, { - "cell_type": "code", - "execution_count": 63, - "id": "looking-cinema", + "cell_type": "markdown", + "id": "ce995609-16c1-4fb3-8f09-8902e7957643", "metadata": {}, - "outputs": [], "source": [ - "a = Student(\"Ольга\")" + "### Декораторы классов" ] }, { "cell_type": "code", - "execution_count": 64, - "id": "varying-contribution", + "execution_count": 67, + "id": "0d96a83f-1640-410e-b9dc-2c8d4809935a", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "'Ольга, 18'" - ] - }, - "execution_count": 64, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Welcome to our university!\n" + ] } ], "source": [ - "a.return_data()" + "class University:\n", + " def __init__(self, name):\n", + " self.name = name\n", + "\n", + " # Статический метод не требует инстанса класса\n", + " @staticmethod\n", + " def say_greeting():\n", + " print(\"Welcome to our university!\")\n", + "\n", + "\n", + "University.say_greeting()" ] }, { "cell_type": "code", - "execution_count": 66, - "id": "sharing-puzzle", + "execution_count": 74, + "id": "adb5e342-0bd8-4916-b63f-58a0134c7d08", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Math', 'English', 'Physics']\n", + "['Math', 'English']\n" + ] + } + ], "source": [ - "class Student:\n", - " _count_students = 0\n", + "class University:\n", + " _subjects = [\"Math\", \"English\", \"Physics\"]\n", "\n", - " def __init__(self, name, age=18):\n", + " def __init__(self, name):\n", " self.name = name\n", - " self.age = age\n", - " Student._count_students += 1\n", "\n", - " # Dunder or magic методы - методы с двумя _ в начале и в конце\n", - " # Эти методы обладают магическими свойствами\n", + " # Класс метод принимает на вход сам класс. Не инстанс!\n", + " @classmethod\n", + " def reduce_subjects(cls):\n", + " cls._subjects.pop()\n", + "\n", + " def get_subjects(self):\n", + " return self._subjects\n", + "\n", "\n", - " # __str__ - применяется к обьекту при вызове str от него\n", - " def __str__(self):\n", - " return self.name + \", \" + str(self.age)" + "misis = University(\"MISIS\")\n", + "print(misis.get_subjects())\n", + "University.reduce_subjects()\n", + "print(misis.get_subjects())" ] }, { "cell_type": "code", - "execution_count": 68, - "id": "level-stevens", + "execution_count": 75, + "id": "6245f3a6-2a3a-4621-bef1-3b817a86a469", "metadata": {}, "outputs": [ { - "data": { - "text/plain": [ - "'Петер, 21'" - ] - }, - "execution_count": 68, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "30\n" + ] } ], "source": [ - "a = Student(\"Петер\", 21)\n", - "str(a)" + "class Rectangle:\n", + " def __init__(self, a, b):\n", + " self.a = a\n", + " self.b = b\n", + "\n", + " # Гетер\n", + " @property\n", + " def area(self):\n", + " return self.a * self.b\n", + "\n", + "\n", + "rect = Rectangle(5, 6)\n", + "print(rect.area)" ] }, { "cell_type": "markdown", - "id": "korean-mitchell", + "id": "733da796-3ca7-42b0-9ccf-94278bcb9699", "metadata": {}, "source": [ - "## Инкапсуляция\n", - "Механизм сокрытия, позволяющий разграничивать доступ к различным компонентам программы. " + "## Итераторы" ] }, { - "cell_type": "code", - "execution_count": 138, - "id": "confirmed-cliff", + "cell_type": "markdown", + "id": "999c9a5e-5f6d-471d-988a-ffde2b07771f", "metadata": {}, - "outputs": [], "source": [ - "class Student:\n", - " _count_students = 0\n", - "\n", - " def __init__(self, name, age=18):\n", - " self.name = name\n", - " self.age = age\n", - " Student._count_students += 1\n", - "\n", - " def __str__(self):\n", - " return self.name + \", \" + str(self.age)\n", + "Итератор (iterator) - это объект, который возвращает свои элементы по одному за раз.\n", "\n", - " # public\n", - " def method_a(self):\n", - " self.d = \"a\"\n", - " return \"a\"\n", + "С точки зрения Python - это любой объект, у которого определены магические методы `__next__` и `__iter__`.\n", "\n", - " # protected\n", - " def _method_b(self):\n", - " return \"b\"\n", + "`__next__` - этот метод возвращает следующий элемент, если он есть, или возвращает исключение StopIteration, когда элементы закончились.\n", "\n", - " # private\n", - " def __method_c(self):\n", - " return \"c\"" + "`__iter__` - этот метод просто возвращает сам итератор." ] }, { "cell_type": "code", - "execution_count": 142, - "id": "residential-theory", + "execution_count": 83, + "id": "1ffa51df-9fde-4954-9a4c-cb13d8ca3923", "metadata": {}, "outputs": [ { - "ename": "AttributeError", - "evalue": "'Student' object has no attribute 'd'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mStudent\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Петер'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m21\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m# Сработает без проблем\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m: 'Student' object has no attribute 'd'" - ] + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 83, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ - "a = Student(\"Петер\", 21)\n", - "# Сработает без проблем\n", - "a.d" + "langs = [\"Python\", \"Golang\", \"C++\"]\n", + "iter(langs)" ] }, { "cell_type": "code", - "execution_count": 72, - "id": "authentic-representative", + "execution_count": 84, + "id": "09a5505d-4aa2-485d-b6f2-99811b91cfcb", "metadata": {}, "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Python\n" + ] + }, { "data": { "text/plain": [ - "'b'" + "['Golang', 'C++']" ] }, - "execution_count": 72, + "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# Сработает без проблем, но большинство IDE подчеркнёт как ошибку\n", - "a._method_b()" + "iter_langs = iter([\"Python\", \"Golang\", \"C++\"])\n", + "print(next(iter_langs))\n", + "list(iter_langs)" ] }, { "cell_type": "code", - "execution_count": 79, - "id": "computational-fabric", + "execution_count": 85, + "id": "5af81694-47d5-4117-b3c6-72b9337ed64b", "metadata": {}, "outputs": [ { - "ename": "AttributeError", - "evalue": "'Student' object has no attribute '__method_c'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# Не сработает\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__method_c\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m: 'Student' object has no attribute '__method_c'" + "name": "stdout", + "output_type": "stream", + "text": [ + "Python\n", + "Golang\n", + "C++\n" ] } ], "source": [ - "# Не сработает\n", - "a.__method_c()" + "langs = [\"Python\", \"Golang\", \"C++\"]\n", + "for lang in iter(langs): # == for lang in langs\n", + " print(lang)" + ] + }, + { + "cell_type": "markdown", + "id": "0f51b3d8-a6d5-4a96-ab94-cade3b7dc868", + "metadata": {}, + "source": [ + "* Зачем нужны итераторы? " ] }, { "cell_type": "code", - "execution_count": 80, - "id": "conditional-supervision", + "execution_count": 96, + "id": "b6356703-211f-4a34-84a8-ee270608f546", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "'c'" + "'Hello\\\\nWorld!\\n'" ] }, - "execution_count": 80, + "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# Но всё равно можно вызвать через ._()\n", - "a._Student__method_c()" + "! echo \"Hello\\nWorld!\" > example.txt\n", + "file = open(\"example.txt\")\n", + "next(file)" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "id": "f67b153f-16c8-4263-b32e-8bfe1793e425", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello\\nWorld!\n" + ] + } + ], + "source": [ + "for line in file:\n", + " print(line.rstrip())" ] }, { "cell_type": "markdown", - "id": "charitable-column", + "id": "47de44b9-1c69-44a5-98b6-612598836d37", "metadata": {}, "source": [ - "## Наследование\n", - "Концепция объектно-ориентированного программирования, согласно которой абстрактный тип данных может наследовать данные и функциональность некоторого существующего типа, способствуя повторному использованию компонентов программного обеспечения.\n", - "\n", - "class <дочерний класс>(<родительский класс>)" + "### Генераторы" + ] + }, + { + "cell_type": "markdown", + "id": "b9ec6ed4-063f-4b06-895d-040da20b2e44", + "metadata": {}, + "source": [ + "Каждый генератор - это итератор, но не наоборот (== генератор это подтип итератора)" ] }, { "cell_type": "code", - "execution_count": 107, - "id": "demographic-trunk", + "execution_count": 99, + "id": "c6754955-ae06-43e8-a303-643fef53c365", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Привет, мир!\n" + "issubclass(Generator, Iterator)=True\n", + "issubclass(Iterator, Generator)=False\n" ] } ], "source": [ - "class A:\n", - " def __init__(self):\n", - " print(\"Привет, мир!\")\n", - "\n", + "from typing import Iterator\n", + "from typing import Generator\n", "\n", - "class B(A):\n", - " pass\n", - "\n", - "\n", - "b = B()" + "print(f\"{issubclass(Generator, Iterator)=}\")\n", + "print(f\"{issubclass(Iterator, Generator)=}\")" + ] + }, + { + "cell_type": "markdown", + "id": "589c78ee-2d22-4bd6-9eed-7d6ec3b6e621", + "metadata": {}, + "source": [ + "#### Генераторное выражение" ] }, { "cell_type": "code", - "execution_count": 108, - "id": "split-disclaimer", + "execution_count": 103, + "id": "1bb497e2-d145-4d63-aa2a-0f8ebb079141", "metadata": {}, "outputs": [], "source": [ - "class C:\n", - " # Члены можно переопределять\n", - " def __init__(self):\n", - " print(\"Привет, жестокий мир\")" + "genexpr = (int(input()) ** 2 for x in range(3)) # ожидания ввода нет" ] }, { "cell_type": "code", - "execution_count": 109, - "id": "spare-bench", + "execution_count": 104, + "id": "16c18eb8-aea2-418d-a8f6-faf341a5453e", + "metadata": {}, + "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + " 123123\n" + ] + }, + { + "data": { + "text/plain": [ + "15159273129" + ] + }, + "execution_count": 104, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "next(genexpr)" + ] + }, + { + "cell_type": "markdown", + "id": "f8c4d178-c5f5-40c0-9c4b-862f15d9a39f", + "metadata": {}, + "source": [ + "#### Функция-генератор" + ] + }, + { + "cell_type": "code", + "execution_count": 155, + "id": "e03fd523-9ad0-4514-8a86-9e13d149928f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Привет, жестокий мир\n" + "Stop execution\n", + "Current number: 1\n", + "Continue execution\n", + "Stop execution\n", + "Current number: 1\n", + "Continue execution\n", + "Stop execution\n", + "Current number: 2\n", + "Continue execution\n", + "Stop execution\n", + "Current number: 3\n", + "Continue execution\n", + "Stop execution\n", + "Current number: 5\n", + "Continue execution\n" ] } ], "source": [ - "c = C()" + "import time\n", + "\n", + "\n", + "def fib(n: int): # числа Фиббоначи\n", + " n_1, n_2 = 1, 1\n", + " for i in range(n):\n", + " print(\"Stop execution\")\n", + " yield n_1\n", + " print(\"Continue execution\")\n", + " n_1, n_2 = n_2, n_1 + n_2\n", + "\n", + "\n", + "for x in fib(5):\n", + " print(\"Current number:\", x)\n", + " time.sleep(1)" + ] + }, + { + "cell_type": "markdown", + "id": "0e5b4047-b41f-4573-8abe-52537fd6bdef", + "metadata": {}, + "source": [ + "## Context manager" + ] + }, + { + "cell_type": "markdown", + "id": "c439d4e7-c83e-472c-aaf8-5ec6d165f0cd", + "metadata": {}, + "source": [ + ">«Контекстные менеджеры в Python — это удивительный механизм, который позволяет гарантировать корректное управление ресурсами и обеспечивать безопасное выполнение кода.» — Гвидо ван Россум, великодушный пожизненный диктатор Python." + ] + }, + { + "cell_type": "markdown", + "id": "13067229-5719-456f-9d99-9209a4278cc8", + "metadata": {}, + "source": [ + "### Работа с файлами" ] }, { "cell_type": "code", - "execution_count": 116, - "id": "pointed-young", + "execution_count": 165, + "id": "703bff85-b978-4fa1-be03-28a307980828", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "(bool, int, object)" + "inf" ] }, - "execution_count": 116, + "execution_count": 165, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# issubclass(X, Y) возвращает True, если X - подкласса класса Y\n", - "issubclass(C, A), issubclass(B, A)" + "def divide(a: float, b: float) -> float:\n", + " try:\n", + " return a / b\n", + " except ZeroDivisionError:\n", + " return float(\"inf\")\n", + "\n", + "\n", + "divide(1, 0)" + ] + }, + { + "cell_type": "code", + "execution_count": 167, + "id": "51d77e86-326e-43bd-b13b-052603feefb0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello\\nWorld!\n", + "\n" + ] + } + ], + "source": [ + "file = open(\"example.txt\", \"r\")\n", + "try:\n", + " # Действия с файлом\n", + " content = file.read()\n", + " print(content)\n", + "finally:\n", + " file.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 169, + "id": "cdfde82d-3d95-47ce-8c1d-14857835d430", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello\\nWorld!\n", + "\n" + ] + } + ], + "source": [ + "with open(\"example.txt\", \"r\") as file:\n", + " content = file.read()\n", + " print(content)\n", + "# --> file.close()" ] }, { "cell_type": "markdown", - "id": "numerous-infection", + "id": "9a599282-ed4c-4d59-b248-7d0168757c4e", "metadata": {}, "source": [ - "## Полиморфизм\n", - "Свойство системы, позволяющее использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта. " + "### Работа с бд" ] }, { "cell_type": "code", - "execution_count": 117, - "id": "laughing-fourth", + "execution_count": 180, + "id": "80c20503-1db4-44f5-a47a-0d448daeaacd", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "BARK\n", - "MEOW\n" + "[(1, 'a'), (2, 'teadove'), (3, 'tainella'), (4, 'teadove'), (5, 'tainella')]\n" ] } ], "source": [ - "class Animal:\n", - " def __init__(self):\n", - " pass\n", + "import sqlite3\n", + "\n", + "# Пример работы с SQLite базой данных\n", + "with sqlite3.connect(\"example.db\") as conn:\n", + " cursor = conn.cursor()\n", + " # Выполнение операций с базой данных\n", + " cursor.execute(\"CREATE TABLE IF NOT EXISTS user(id INTEGER PRIMARY KEY, name TEXT)\")\n", + " cursor.execute(\"INSERT INTO user(name) VALUES ('teadove'), ('tainella')\")\n", + " cursor.execute(\"SELECT * FROM user\")\n", + " result = cursor.fetchall()\n", + " print(result)" + ] + }, + { + "cell_type": "markdown", + "id": "b42b5bf0-a7e6-422a-b62f-513f8c36b556", + "metadata": {}, + "source": [ + "### Свой контекстный менеджер" + ] + }, + { + "cell_type": "markdown", + "id": "593f3cad-5b5d-493e-a9a5-4c7078ff675f", + "metadata": {}, + "source": [ + "Контекстный менеджер в Python должен содержать методы `__enter__` и `__exit__`.\n", "\n", - " def bark(self):\n", - " pass\n", + "Метод `__enter__` выполняется перед выполнением блока кода внутри оператора with. Он может выполнять какие-либо подготовительные действия или возвращать значение, которое будет связано с переменной после ключевого слова as.\n", "\n", + "Метод `__exit__` вызывается после завершения выполнения блока кода with. Он используется для выполнения завершающих действий, таких как освобождение ресурсов, обработка исключений или выполнение финализирующих операций." + ] + }, + { + "cell_type": "code", + "execution_count": 181, + "id": "2aa714da-b364-40d7-a0b2-43d03185d08f", + "metadata": {}, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'ContextManager' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[181], line 10\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__exit__\u001b[39m(\u001b[38;5;28mself\u001b[39m, exc_type, exc_value, exc_traceback): \n\u001b[1;32m 7\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mexit method called\u001b[39m\u001b[38;5;124m'\u001b[39m) \n\u001b[0;32m---> 10\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[43mContextManager\u001b[49m() \u001b[38;5;28;01mas\u001b[39;00m manager: \n\u001b[1;32m 11\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mwith statement block\u001b[39m\u001b[38;5;124m'\u001b[39m) \n", + "\u001b[0;31mNameError\u001b[0m: name 'ContextManager' is not defined" + ] + } + ], + "source": [ + "class ErrorMutter:\n", + " def __enter__(self):\n", + " print(\"enter method called\")\n", + " return self\n", "\n", - "class Cat(Animal):\n", - " def bark(self):\n", - " return \"MEOW\"\n", + " def __exit__(self, exc_type, exc_value, exc_traceback):\n", + " print(\"exit method called\")\n", "\n", "\n", - "class Dog(Animal):\n", - " def bark(self):\n", - " return \"BARK\"\n", + "with ContextManager() as manager:\n", + " print(\"with statement block\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc214333-aa10-4a9f-b5cb-548b3a902b4b", + "metadata": {}, + "outputs": [], + "source": [ + "class FileManager:\n", + " def __init__(self, filename, mode):\n", + " self.filename = filename\n", + " self.mode = mode\n", + " self.file = None\n", "\n", + " def __enter__(self):\n", + " self.file = open(self.filename, self.mode)\n", + " return self.file\n", "\n", - "def do_voice(animal):\n", - " print(animal.bark())\n", + " def __exit__(self, exc_type, exc_value, exc_traceback):\n", + " self.file.close()\n", "\n", "\n", - "kraft = Dog()\n", - "do_voice(kraft)\n", + "# загрузка файла\n", + "with FileManager(\"example.txt\", \"r\") as f:\n", + " print(f.encoding)\n", "\n", - "mikki = Cat()\n", - "do_voice(mikki)" + "print(f.closed)" ] }, { - "cell_type": "markdown", - "id": "waiting-excellence", + "cell_type": "code", + "execution_count": 17, + "id": "64872ea5-7543-4cd8-ae97-859bcff8263d", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "enter method called\n", + "with statement block\n", + "exit method called\n" + ] + } + ], "source": [ - "## Декораторы\n", - "Это функции, оборачивающие другие функции" + "from contextlib import contextmanager\n", + "\n", + "\n", + "@contextmanager\n", + "def context_manager():\n", + " # Внутри вызова __enter__\n", + " print(\"enter method called\")\n", + " try:\n", + " yield\n", + " finally:\n", + " # Внутри вызова __exit__\n", + " print(\"exit method called\")\n", + "\n", + "\n", + "with context_manager() as manager:\n", + " print(\"with statement block\")" ] }, { "cell_type": "code", - "execution_count": 121, - "id": "given-authentication", + "execution_count": 20, + "id": "2da3fc20-7115-4142-89cb-b22898a18f9d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Elapsed time: 0.1904282569885254\n" + ">entering the context manager\n", + "within the manager\n", + ">exiting the context manager\n" ] } ], "source": [ - "# import - подключение библеотек, как #include c/с++\n", - "import time\n", + "import asyncio\n", "\n", "\n", - "def timeit(func):\n", - " def wrapper_func(*args, **kwargs):\n", - " start = time.time() # time.time текущее время в секундах отсчитывая c 1970 года\n", - " func(*args, **kwargs)\n", - " end = time.time()\n", - " print(f\"Elapsed time: {end - start}\")\n", + "# определение асинхронного менеджера контекста\n", + "class AsyncContextManager:\n", + " # вход в асинхронный менеджер контекста\n", + " async def __aenter__(self):\n", + " # вывод сообщения\n", + " print(\">entering the context manager\")\n", + " # блокировка на некоторое время\n", + " await asyncio.sleep(0.5)\n", "\n", - " return wrapper_func\n", + " # выход из асинхронного менеджера контекста\n", + " async def __aexit__(self, exc_type, exc, tb):\n", + " # вывод сообщения\n", + " print(\">exiting the context manager\")\n", + " # блокировка на некоторое время\n", + " await asyncio.sleep(0.5)\n", "\n", "\n", - "def count(a=10_000_000):\n", - " for i in range(a):\n", - " pass\n", + "# определение простой корутины\n", + "async def custom_coroutine():\n", + " # создание и использование асинхронного менеджера контекста\n", + " async with AsyncContextManager() as manager:\n", + " # вывод результирующего сообщения\n", + " print(f\"within the manager\")\n", "\n", "\n", - "timed_count = timeit(count)\n", - "timed_count(10_000_000)" + "# запуск asyncio-программы\n", + "await custom_coroutine()" ] }, { - "cell_type": "code", - "execution_count": 145, - "id": "alien-recipe", + "cell_type": "markdown", + "id": "b8d3f36c-93bc-402b-83aa-715cf6b69a27", + "metadata": { + "jp-MarkdownHeadingCollapsed": true + }, + "source": [ + "## Доп. материалы" + ] + }, + { + "cell_type": "markdown", + "id": "5643ef41-b77d-40da-9578-706bdac53020", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 145, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "def f():\n", - " return True, False\n", + "[Статья про декораторы и генераторы от Яндекса](https://academy.yandex.ru/handbook/python/article/rekursiya-dekoratory-generatory)\n", + "\n", + "[Некоторые хитрости при работе с итераторами](https://habr.com/ru/articles/488112/)\n", + "\n", + "[Подробнее про context manager и его применения](https://realpython.com/python-with-statement/)\n", "\n", + "Для продвинутых: \n", "\n", - "a, _ = f()\n", - "a" + "[Интересная статья про асинхронность: контекстные менеджеры и не только](https://habr.com/ru/companies/wunderfund/articles/711012/)" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -610,7 +980,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.10.12" } }, "nbformat": 4,