From d6ab84e93a33604be60ade2a49894dbde0ba5009 Mon Sep 17 00:00:00 2001 From: hasan613 Date: Wed, 22 Apr 2026 14:42:22 +0300 Subject: [PATCH 1/2] [TASK 1] Python (https://github.com/SENATOROVAI/python/issues/1) Closes SENATOROVAI/python#1 --- python/clean-code/ch4_var_names.ipynb | 126 + python/clean-code/ch4_var_names.py | 126 + python/makarov/chapter_15_iterators.ipynb | 1410 +++++++++ python/makarov/chapter_15_iterators.py | 329 ++ python/makarov/chapter_16_decorators.ipynb | 2068 +++++++++++++ python/makarov/chapter_16_decorators.py | 685 ++++ python/makarov/chapter_1_var.ipynb | 492 +++ python/makarov/chapter_1_var.py | 140 + python/makarov/chapter_2_dtype.ipynb | 563 ++++ python/makarov/chapter_2_dtype.py | 204 ++ python/makarov/chapter_3_loop.ipynb | 1085 +++++++ python/makarov/chapter_3_loop.py | 489 +++ python/makarov/chapter_4_gcollab.ipynb | 352 +++ python/makarov/chapter_4_gcollab.py | 201 ++ python/makarov/chapter_5_date.ipynb | 644 ++++ python/makarov/chapter_5_date.py | 289 ++ python/makarov/chapter_6_func.ipynb | 2081 +++++++++++++ python/makarov/chapter_6_func.py | 633 ++++ python/makarov/chapter_7_oop.ipynb | 922 ++++++ python/makarov/chapter_7_oop.py | 625 ++++ .../makarov/chapter_8_lists_tuples_sets.ipynb | 2544 +++++++++++++++ python/makarov/chapter_8_lists_tuples_sets.py | 537 ++++ python/makarov/chapter_9_dictionaries.ipynb | 2750 +++++++++++++++++ python/makarov/chapter_9_dictionaries.py | 609 ++++ python/oop.ipynb | 404 +++ python/oop.py | 143 + 26 files changed, 20451 insertions(+) create mode 100644 python/clean-code/ch4_var_names.ipynb create mode 100644 python/clean-code/ch4_var_names.py create mode 100644 python/makarov/chapter_15_iterators.ipynb create mode 100644 python/makarov/chapter_15_iterators.py create mode 100644 python/makarov/chapter_16_decorators.ipynb create mode 100644 python/makarov/chapter_16_decorators.py create mode 100644 python/makarov/chapter_1_var.ipynb create mode 100644 python/makarov/chapter_1_var.py create mode 100644 python/makarov/chapter_2_dtype.ipynb create mode 100644 python/makarov/chapter_2_dtype.py create mode 100644 python/makarov/chapter_3_loop.ipynb create mode 100644 python/makarov/chapter_3_loop.py create mode 100644 python/makarov/chapter_4_gcollab.ipynb create mode 100644 python/makarov/chapter_4_gcollab.py create mode 100644 python/makarov/chapter_5_date.ipynb create mode 100644 python/makarov/chapter_5_date.py create mode 100644 python/makarov/chapter_6_func.ipynb create mode 100644 python/makarov/chapter_6_func.py create mode 100644 python/makarov/chapter_7_oop.ipynb create mode 100644 python/makarov/chapter_7_oop.py create mode 100644 python/makarov/chapter_8_lists_tuples_sets.ipynb create mode 100644 python/makarov/chapter_8_lists_tuples_sets.py create mode 100644 python/makarov/chapter_9_dictionaries.ipynb create mode 100644 python/makarov/chapter_9_dictionaries.py create mode 100644 python/oop.ipynb create mode 100644 python/oop.py diff --git a/python/clean-code/ch4_var_names.ipynb b/python/clean-code/ch4_var_names.ipynb new file mode 100644 index 00000000..e035e3b0 --- /dev/null +++ b/python/clean-code/ch4_var_names.ipynb @@ -0,0 +1,126 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "id": "0e99d094", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Var names chapter 4.'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Var names chapter 4.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "445ee8d7", + "metadata": {}, + "source": [ + "\"Трудно придумать хорошие имена (формально называемые идентификаторами) для переменных, функций, классов и вообще чего угодно в програм-\n", + "мировании.\"\n", + "\n", + "#### Схемы регистра имен\n", + "1. Змеиный регистр (snake_case) разделяет слова символом подчеркивания, который напоминает ползущую между словами змею. Константы часто записываются в верхнем змеином регистре (UPPER_SNAKE_CASE).\n", + "2. Верблюжий регистр (camelCase) — слова записываются в нижнем регистре, но второе и следующие слова начинаются с заглавной.\n", + "3. Схема Pascal (PascalCase) — аналогична схеме верблюжьего регистра, но первое слово в ней тоже начинается с заглавной.\n", + "\n", + "- использую змеиный регистр\n", + "\n", + "#### Соглашения об именах PEP 8\n", + "- Все буквы должны быть буквами ASCII — то есть латинскими буквами верхнего и нижнего регистров без диакритических знаков.\n", + "- Имена модулей должны быть короткими и состоять только из букв нижнего регистра.\n", + "- Имена констант следует записывать в верхнем змеином регистре.\n", + "- Имена классов необходимо записывать в схеме Pascal.\n", + "- Имена функций, методов и переменных записывают в нижнем змеином регистре.\n", + "- Первый аргумент методов всегда должен называться self в нижнем регистре.\n", + "- Первый аргумент методов классов всегда должен называться cls в нижнем регистре.\n", + "- Приватные атрибуты классов всегда начинают с символа подчеркивания ( _ ).\n", + "- Публичные атрибуты классов никогда не начинают с символа подчеркивания ( _ ).\n", + "\n", + "#### Длина имен\n", + "Очевидно, имена не должны быть слишком короткими или слишком длинными. Но так как код читают чаще, чем пишут, лучше все-таки задавать более длинные имена переменных и функций.\n", + "\n", + "##### Слишком короткие имена\n", + "1. Одно- или двухбуквенное имя (например, g), вероятно, обозначает какое-то слово, начинающееся с этой буквы, но таких слов очень много. Сокращения и одно-двухбуквенные имена легко записать, но они плохо читаются. Это замечание относится и к следующему пункту.\n", + "2. Сокращенные имена вида mon — могут означать monitor, month, monster и множество других слов.\n", + "3. Имя из одного слова — например, start (начало) — может трактоваться по разному: начало чего? При отсутствии уточнения другие люди вас вряд ли поймут.\n", + "\n", + "В отдельных случаях короткие имена переменных вполне допустимы (временная переменная в цикле for()). Еще одно исключение — использование x и y для декартовых координат.\n", + "\n", + "##### Слишком длинные имена\n", + "Короткое имя (например, payment) хорошо подойдет для локальной переменной в одной короткой функции. Для глобальной переменной\n", + "лучше использовать более содержательное имя salesClientMonthlyPayment или annual_electric_bill_payment. Дополнительные слова в имени уточняют смысл и устраняют неоднозначность.\n", + "\n", + "Не пропускайте буквы в своем коде. (в названии переменных)\n", + "\n", + "##### Префиксы в именах\n", + "Префиксы is и has у переменных, содержащих логические значения, или функций и методов, возвращающих логические значения, делают эти имена более понятными. Также включение единиц измерения в имена может предоставить полезную информацию.\n", + "\n", + "##### Последовательные числовые суффиксы в именах\n", + "Последовательные числовые суффиксы в именах указывают на то, что вам, возможно, стоит изменить тип данных переменной или включить дополнительную информацию в имя. Числа сами по себе, как правило, не предоставляют достаточной информации, чтобы имена можно было отличить друг от друга.\n", + "\n", + "Имена переменных вида payment1, payment2 и payment3 не сообщают читателю кода, чем они различаются. - это ужасно!\n", + "\n", + "##### Выбирайте имена, пригодные для поиска\n", + "Чтобы имя было найдено немедленно, создавайте уникальные имена с более длинными именами переменных, которые содержат конкретную информацию. (для поиска через Ctrl+F в IDE)\n", + "\n", + "##### Избегайте шуток, каламбуров и культурных отсылок\n", + "При выборе имен в программе у вас может возникнуть соблазн использовать шутки, каламбуры или культурные отсылки, чтобы ваш код выглядел более непринужденно. Не делайте этого.\n", + "\n", + "##### Не заменяйте встроенные имена\n", + "Никогда не используйте встроенные имена Python для своих переменных. \n", + "Например, присвоив переменной имя list или set, вы заместите функции Python list()\n", + "и set(), что позднее может привести к появлению ошибок.\n", + "\n", + "Наиболее часто заменяемые имена Python — all, any, date, email, file, format, hash,\n", + "id, input, list, min, max, object, open, random, set, str, sum, test и type. Не берите их для своих идентификаторов.\n", + "\n", + "Другая распространенная проблема — присваивание файлам .py имен, совпадающих с именами сторонних модулей. Например, если вы установили сторонний модуль Pyperclip, но также создали файл pyperclip.py, команда import pyperclip импортирует pyperclip.py вместо модуля Pyperclip. При попытке вызвать функцию copy() или paste() модуля Pyperclip вы получите ошибку, в которой говорится, что функции не существует.\n", + "\n", + "\n", + "##### Худшие из возможных имен\n", + "Имя data — ужасное и абсолютно бессодержательное, потому что буквально любая переменная содержит данные (data). То же можно сказать об имени var — все равно что выбрать для собаки кличку Собака.\n", + "\n", + "Если вам нужна переменная для хранения статистического отклонения температурных данных, используйте имя temperatureVariance. Не стоит и говорить, что выбор имени tempVarData будет неудачным.\n", + "\n", + "\n", + "##### Итоги\n", + "Выбор имен - это важнейший фактор написания удобочитаемого кода. В PEP 8 вы найдете несколько соглашений о выборе имен — например, имена в нижнем регистре для модулей и имена в схеме Pascal для классов. Имена не должны быть слишком короткими или слишком длинными. Однако часто лучше сделать имя избыточным, чем недостаточно содержательным.\n", + "\n", + "Избегайте имен, уже используемых стандартной библиотекой Python\n", + "Использование понятных имен — основополагающий фактор разработки качественного программного обеспечения.\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/clean-code/ch4_var_names.py b/python/clean-code/ch4_var_names.py new file mode 100644 index 00000000..ba506d07 --- /dev/null +++ b/python/clean-code/ch4_var_names.py @@ -0,0 +1,126 @@ +"""Var names chapter 4.""" + +# "Трудно придумать хорошие имена (формально называемые идентификаторами) +# для переменных, функций, классов и вообще чего угодно в програм- +# мировании." +# +# #### Схемы регистра имен +# 1. Змеиный регистр (snake_case) разделяет слова символом подчеркивания, +# который напоминает ползущую между словами змею. Константы часто записываются +# в верхнем змеином регистре (UPPER_SNAKE_CASE). +# 2. Верблюжий регистр (camelCase) — слова записываются в нижнем регистре, но +# второе и следующие слова начинаются с заглавной. +# 3. Схема Pascal (PascalCase) — аналогична схеме верблюжьего регистра, но +# первое слово в ней тоже начинается с заглавной. +# +# - использую змеиный регистр +# +# #### Соглашения об именах PEP 8 +# - Все буквы должны быть буквами ASCII — то есть латинскими буквами верхнего +# и нижнего регистров без диакритических знаков. +# - Имена модулей должны быть короткими и состоять только из букв нижнего +# регистра. +# - Имена констант следует записывать в верхнем змеином регистре. +# - Имена классов необходимо записывать в схеме Pascal. +# - Имена функций, методов и переменных записывают в нижнем змеином регистре. +# - Первый аргумент методов всегда должен называться self в нижнем регистре. +# - Первый аргумент методов классов всегда должен называться cls в нижнем +# регистре. +# - Приватные атрибуты классов всегда начинают с символа подчеркивания ( _ ). +# - Публичные атрибуты классов никогда не начинают с символа подчеркивания +# ( _ ). +# +# #### Длина имен +# Очевидно, имена не должны быть слишком короткими или слишком длинными. +# Но так как код читают чаще, чем пишут, лучше все-таки задавать более +# длинные имена переменных и функций. +# +# ##### Слишком короткие имена +# 1. Одно- или двухбуквенное имя (например, g), вероятно, обозначает какое-то +# слово, начинающееся с этой буквы, но таких слов очень много. Сокращения и +# одно-двухбуквенные имена легко записать, но они плохо читаются. Это +# замечание относится и к следующему пункту. +# 2. Сокращенные имена вида mon — могут означать monitor, month, monster и +# множество других слов. +# 3. Имя из одного слова — например, start (начало) — может трактоваться по +# разному: начало чего? При отсутствии уточнения другие люди вас вряд ли +# поймут. +# +# В отдельных случаях короткие имена переменных вполне допустимы (временная +# переменная в цикле for()). Еще одно исключение — использование x и y для +# декартовых координат. +# +# ##### Слишком длинные имена +# Короткое имя (например, payment) хорошо подойдет для локальной переменной в +# одной короткой функции. Для глобальной переменной +# лучше использовать более содержательное имя salesClientMonthlyPayment или +# annual_electric_bill_payment. Дополнительные слова в имени уточняют смысл и +# устраняют неоднозначность. +# +# Не пропускайте буквы в своем коде. (в названии переменных) +# +# ##### Префиксы в именах +# Префиксы is и has у переменных, содержащих логические значения, или функций +# и методов, возвращающих логические значения, делают эти имена более +# понятными. Также включение единиц измерения в имена может предоставить +# полезную информацию. +# +# ##### Последовательные числовые суффиксы в именах +# Последовательные числовые суффиксы в именах указывают на то, что вам, +# возможно, стоит изменить тип данных переменной или включить дополнительную +# информацию в имя. Числа сами по себе, как правило, не предоставляют +# достаточной информации, чтобы имена можно было отличить друг от друга. +# +# Имена переменных вида payment1, payment2 и payment3 не сообщают читателю +# кода, чем они различаются. - это ужасно! +# +# ##### Выбирайте имена, пригодные для поиска +# Чтобы имя было найдено немедленно, создавайте уникальные имена с более +# длинными именами переменных, которые содержат конкретную информацию. (для +# поиска через Ctrl+F в IDE) +# +# ##### Избегайте шуток, каламбуров и культурных отсылок +# При выборе имен в программе у вас может возникнуть соблазн использовать +# шутки, каламбуры или культурные отсылки, чтобы ваш код выглядел более +# непринужденно. Не делайте этого. +# +# ##### Не заменяйте встроенные имена +# Никогда не используйте встроенные имена Python для своих переменных. +# Например, присвоив переменной имя list или set, вы заместите функции Python +# list() +# и set(), что позднее может привести к появлению ошибок. +# +# Наиболее часто заменяемые имена Python — all, any, date, email, file, +# format, hash, +# id, input, list, min, max, object, open, random, set, str, sum, test и type. +# Не берите их для своих идентификаторов. +# +# Другая распространенная проблема — присваивание файлам .py имен, совпадающих +# с именами сторонних модулей. Например, если вы установили сторонний модуль +# Pyperclip, но также создали файл pyperclip.py, команда import pyperclip +# импортирует pyperclip.py вместо модуля Pyperclip. При попытке вызвать +# функцию copy() или paste() модуля Pyperclip вы получите ошибку, в которой +# говорится, что функции не существует. +# +# +# ##### Худшие из возможных имен +# Имя data — ужасное и абсолютно бессодержательное, потому что буквально любая +# переменная содержит данные (data). То же можно сказать об имени var — все +# равно что выбрать для собаки кличку Собака. +# +# Если вам нужна переменная для хранения статистического отклонения +# температурных данных, используйте имя temperatureVariance. Не стоит и +# говорить, что выбор имени tempVarData будет неудачным. +# +# +# ##### Итоги +# Выбор имен - это важнейший фактор написания удобочитаемого кода. В PEP 8 вы +# найдете несколько соглашений о выборе имен — например, имена в нижнем +# регистре для модулей и имена в схеме Pascal для классов. Имена не должны +# быть слишком короткими или слишком длинными. Однако часто лучше сделать имя +# избыточным, чем недостаточно содержательным. +# +# Избегайте имен, уже используемых стандартной библиотекой Python +# Использование понятных имен — основополагающий фактор разработки +# качественного программного обеспечения. +# diff --git a/python/makarov/chapter_15_iterators.ipynb b/python/makarov/chapter_15_iterators.ipynb new file mode 100644 index 00000000..1ca189f9 --- /dev/null +++ b/python/makarov/chapter_15_iterators.ipynb @@ -0,0 +1,1410 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"Макаров.\n", + "\n", + "Итераторы и генераторы.\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0AoPSXyUTTLc" + }, + "source": [ + "## Итераторы и генераторы" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5Vlh7nreAD2D" + }, + "source": [ + "### Итерируемый объект и итератор" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kthx3B9dGQY5" + }, + "source": [ + "#### Основные определения" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "lgrM3Gnp25o-", + "outputId": "916aa0be-5648-4449-8910-127bffe16165" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "from collections.abc import Iterator\n", + "from itertools import chain, count, cycle\n", + "from typing import Generator\n", + "\n", + "for index in [1, 2, 3]:\n", + " print(index)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YOd5fX1T4VDs", + "outputId": "fda5b2fd-f3ca-40b6-d5e5-782e899731e3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# встроенная функция iter() вызывает метод .__iter__(),\n", + "# создающий итератор\n", + "iterator1 = iter([1, 2, 3])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1s_bw0wr6dn_", + "outputId": "85e8b0e2-a4cd-443d-a699-e52cf88dbd66" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "iterable_object: list[int] = [1, 2, 3]\n", + "\n", + "iterator = iter(iterable_object)\n", + "print(iterator)\n", + "print()\n", + "\n", + "print(next(iterator))\n", + "print(next(iterator))\n", + "print(next(iterator))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tbGGt-NK8Scw", + "outputId": "b51b2e38-fe17-4362-cc76-2a1e5adfb6b9" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "for iterator2 in iterable_object:\n", + " print(iterator2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "fPbwZ8UO93lC", + "outputId": "bee708e4-d96a-4409-b9d9-4884ecd6851d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "A: 1\n", + "A: 2\n", + "A: 3\n", + "B: 1\n" + ] + } + ], + "source": [ + "iterator_a = iter(iterable_object)\n", + "iterator_b = iter(iterable_object)\n", + "\n", + "print(f\"A: {next(iterator_a)}\")\n", + "print(f\"A: {next(iterator_a)}\")\n", + "print(f\"A: {next(iterator_a)}\")\n", + "print(f\"B: {next(iterator_b)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HkVfe8K3CSD3", + "outputId": "fe0d9740-3d21-43fc-8992-85d88c4f31f3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "iterable_object" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gPsw6ywr_642" + }, + "outputs": [], + "source": [ + "# print(f'A: {next(iterator_a)}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PFhBl_4Cx06v", + "outputId": "d30c68e5-c78d-4aed-8c9d-5517438785ce" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([], [2, 3])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(list(iterator_a), list(iterator_b))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ahG3y2qmgY7i", + "outputId": "d6cd205d-d974-4af5-94d4-895e1ece8d57" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "for item_s in {1, 1, 2, 3}: # pylint: disable=C0208,W0130\n", + " print(item_s)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Sj4h2zyAJTGd" + }, + "source": [ + "#### Отсутствие \"обратного хода\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0SBq2VSKJQkl", + "outputId": "a3e37ec9-7506-4dbe-e1e5-3ac827ddc2cb" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "iterator_c = iter(iterable_object)\n", + "\n", + "for item_c_1 in iterator_c:\n", + " print(item_c_1)\n", + " break\n", + "\n", + "for item_c_2 in iterator_c:\n", + " print(item_c_2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KvUcGyCOF2dl" + }, + "source": [ + "#### Функция `zip()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "G-Z4ToVzFe0n", + "outputId": "403a9165-5fa7-487e-9b82-6d44fd8b73af" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "iterator_tuple = zip(iterable_object, iterable_object)\n", + "print(iterator_tuple)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1Zici5FDGpCL", + "outputId": "6be383b2-6215-4b94-93d5-18b2b6faa4f8" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 1)\n", + "(2, 2)\n", + "(3, 3)\n" + ] + } + ], + "source": [ + "print(next(iterator_tuple))\n", + "print(next(iterator_tuple))\n", + "print(next(iterator_tuple))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Gf2CXrVGFU2I", + "outputId": "c4995972-8e75-4246-b694-9437af79c838" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 1)\n", + "(2, 2)\n", + "(3, 3)\n" + ] + } + ], + "source": [ + "for item_z in zip(iterable_object, iterable_object):\n", + " print(item_z)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "e9y3-HUEKlXe" + }, + "source": [ + "#### Примеры итераторов" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GiQAx3rds0-3" + }, + "source": [ + "Возведение в квадрат" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Gp1fVFW3qJwE" + }, + "outputs": [], + "source": [ + "class Square:\n", + " \"\"\"Итератор, возводящий в квадрат числа из переданной последовательности.\"\"\"\n", + "\n", + " def __init__(self, seq: list[int]) -> None:\n", + " \"\"\"Инициализация итератора.\"\"\"\n", + " self._seq = seq\n", + " self._idx = 0\n", + "\n", + " def __iter__(self) -> \"Square\":\n", + " \"\"\"Возвращает сам объект как итератор.\"\"\"\n", + " return self\n", + "\n", + " def __next__(self) -> int:\n", + " \"\"\"Возвращает следующее значение итератора.\"\"\"\n", + " if self._idx < len(self._seq):\n", + " square = self._seq[self._idx] ** 2\n", + " self._idx += 1\n", + " return square\n", + "\n", + " raise StopIteration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tO8DeWnSqmSZ", + "outputId": "987af348-d6ab-417d-c4b9-99599e2f87b7" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Square at 0x7ec755cf6450>" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "square_1 = Square([1, 2, 3, 4, 5])\n", + "print(square_1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "o2PxHYNJqt6I", + "outputId": "0e717160-6d5c-4d95-d6dc-d0e3137e4d47" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "4\n", + "9\n", + "16\n", + "25\n" + ] + } + ], + "source": [ + "for num_square in square_1:\n", + " print(num_square)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oUor5ZgJs3r3" + }, + "source": [ + "Счетчик" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "k3PWHN0xKoO6" + }, + "outputs": [], + "source": [ + "class Counter:\n", + " \"\"\"Итератор, генерирующий последовательность целых чисел в заданном диапазоне.\"\"\"\n", + "\n", + " def __init__(self, start: int = 3, stop: int = 9) -> None:\n", + " \"\"\"Инициализирует итератор с заданными границами диапазона.\"\"\"\n", + " self._current = start - 1\n", + " self._stop = stop\n", + "\n", + " def __iter__(self) -> \"Counter\":\n", + " \"\"\"Возвращает сам объект как итератор.\"\"\"\n", + " return self\n", + "\n", + " def __next__(self) -> int:\n", + " \"\"\"Возвращает следующее значение в последовательности.\"\"\"\n", + " self._current += 1\n", + " if self._current < self._stop:\n", + " return self._current\n", + "\n", + " raise StopIteration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "g-8TFk7MKzjJ", + "outputId": "2cde6f1e-b01c-432c-c90d-354b589a8990" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "<__main__.Counter at 0x7ec755d18490>" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "counter = Counter()\n", + "print(counter)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "B8LRePjDLZA_", + "outputId": "7eb4976f-30f1-4fd4-84dc-3f2d98d4b6d6" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "4\n" + ] + } + ], + "source": [ + "print(next(counter))\n", + "print(next(counter))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nWMjrjAzeuOk", + "outputId": "6ed0a768-e606-453e-ff5d-f06c5040b3a6" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "6\n", + "7\n", + "8\n" + ] + } + ], + "source": [ + "for current_count in counter:\n", + " print(current_count)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XQ79dGrps8_v" + }, + "source": [ + "Класс Iterator модуля collections.abc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "10ZltZGVtEFo" + }, + "outputs": [], + "source": [ + "class Counter2(Iterator[int]):\n", + " \"\"\"Итератор.\n", + "\n", + " Генерирует последовательность целых чисел в заданном диапазоне.\n", + " \"\"\"\n", + "\n", + " def __init__(self, start: int = 3, stop: int = 9) -> None:\n", + " \"\"\"Инициализирует итератор с заданными границами диапазона.\"\"\"\n", + " self._current = start - 1\n", + " self._stop = stop\n", + "\n", + " def __next__(self) -> int:\n", + " \"\"\"Возвращает следующее значение в последовательности.\"\"\"\n", + " self._current += 1\n", + " if self._current < self._stop:\n", + " return self._current\n", + "\n", + " raise StopIteration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "zYVob0XttPTm", + "outputId": "9513ea1b-3b75-4f89-eff3-59b0a11e9e10" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "4\n", + "5\n", + "6\n", + "7\n", + "8\n" + ] + } + ], + "source": [ + "for current_count in Counter2():\n", + " print(current_count)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "F5EjaYegFtQf" + }, + "source": [ + "Бесконечный итератор" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1K9r-t9jFvZB" + }, + "outputs": [], + "source": [ + "class FibIterator:\n", + " \"\"\"Бесконечный Итератор.\n", + "\n", + " Генерирует последовательность целых чисел, начиная с 0.\n", + " \"\"\"\n", + "\n", + " def __init__(self) -> None:\n", + " \"\"\"Инициализирует итератор.\"\"\"\n", + " self._idx = 0\n", + " self._current = 0\n", + " self._next = 1\n", + "\n", + " def __iter__(self) -> \"FibIterator\":\n", + " \"\"\"Возвращает сам объект как итератор.\"\"\"\n", + " return self\n", + "\n", + " def __next__(self) -> int:\n", + " \"\"\"Возвращает следующее значение в последовательности.\"\"\"\n", + " self._idx += 1\n", + " self._current, self._next = (self._next, self._current + self._next)\n", + " return self._current" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "13nuDa2SG2sK", + "outputId": "de87755e-ed16-447f-9a2b-cefc0fc7a12a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "1\n", + "2\n", + "3\n", + "5\n", + "8\n", + "13\n", + "21\n", + "34\n", + "55\n" + ] + } + ], + "source": [ + "limit = 10\n", + "\n", + "for item_f in FibIterator():\n", + " print(item_f)\n", + " limit -= 1\n", + " if limit == 0:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "i4lNIXO_Edk7" + }, + "source": [ + "### Генератор" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CWU2zNr6-1AZ" + }, + "source": [ + "#### Простой пример" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "g38UdGuA9TRD" + }, + "outputs": [], + "source": [ + "def sequence(end: int) -> list[int]:\n", + " \"\"\"Возвращает список целых чисел от 1 до n включительно.\"\"\"\n", + " res = [num for num in range(1, end + 1)]\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Qk2gw-wH9dUa", + "outputId": "13911636-550d-4ff0-81a6-95a8ee420a52" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(sequence(5))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kX__mcgp8WJm" + }, + "outputs": [], + "source": [ + "def sequence_gen(num_arg: int) -> Generator[int, None, None]:\n", + " \"\"\"Генератор, возвращающий целые числа от 1 до n включительно.\"\"\"\n", + " yield from range(1, num_arg + 1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Cajg_qXU8oPt", + "outputId": "66943925-5e95-42c8-8b93-d5cdd7b53a85" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(sequence_gen(5))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rOKU_bf68uP8", + "outputId": "253bc200-2441-4cab-f7a5-b0f0308b13a0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n" + ] + } + ], + "source": [ + "seq_5 = sequence_gen(5)\n", + "\n", + "print(next(seq_5))\n", + "print(next(seq_5))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "d573ZcOZ8yty", + "outputId": "2f2cb9ef-7348-44ac-ebb0-fd47642f93e2" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "4\n", + "5\n" + ] + } + ], + "source": [ + "for item_s in seq_5:\n", + " print(item_s)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "9iW5ZNZuORsE" + }, + "outputs": [], + "source": [ + "# next(seq_5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mFFbJfjvD27P" + }, + "source": [ + "#### Generator comprehension" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xGCSq8C4BLDQ", + "outputId": "e7c42fd1-39a5-4394-b844-28197b61c6c0" + }, + "outputs": [ + { + "data": { + "text/plain": [ + " at 0x7ec755ccfe00>" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(num for num in range(1, 5 + 1))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "33g4ikqqFcKJ", + "outputId": "4e36c66e-6fe5-4162-fc81-1acf2c15bc61" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1, 2, 3, 4, 5]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(list(num for num in range(1, 5 + 1)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DyOGWjE2LrWx", + "outputId": "91736c7b-c50a-4990-cbc5-b81593c40586" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "15" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(sum(num for num in range(1, 5 + 1)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nzxrUQmEMR27", + "outputId": "f60aaee5-4be5-4905-f85e-4487d6d683b3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(5 in (num for num in range(1, 5 + 1)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dh__pqr-ImTX" + }, + "source": [ + "### Модуль itertools" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zKzMJtVeLHp0" + }, + "source": [ + "#### Функция `count()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "MzPekSQWJBPi", + "outputId": "46fd6fd0-3129-4109-dad8-e4939e62bf0c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "1.5\n", + "2.0\n" + ] + } + ], + "source": [ + "natural_numbers = count(start=1, step=0.5)\n", + "\n", + "for num in natural_numbers:\n", + " print(num)\n", + " if num == 2:\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DbmVDVFKnTlx", + "outputId": "4d7874e9-96fc-4e36-f445-55f4fc341c79" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(0, 'A')\n", + "(1, 'B')\n", + "(2, 'C')\n", + "(3, 'D')\n" + ] + } + ], + "source": [ + "list_: list[str] = [\"A\", \"B\", \"C\", \"D\"]\n", + "for item_1 in zip(count(), list_):\n", + " print(item_1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nKQCJ_hhoJaH", + "outputId": "a9cdc460-6cd9-4595-de7a-a8525207d65a" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "-2" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def quadratic_poly(num_arg: int) -> int:\n", + " \"\"\"Вычисляет значение квадратичной функции f(x) = x² + x - 2.\"\"\"\n", + " return num_arg**2 + num_arg - 2\n", + "\n", + "\n", + "f_x = map(quadratic_poly, count())\n", + "next(f_x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nmLgF8Xio_Kd", + "outputId": "8c8407b8-8043-4ef5-b12c-13402ac22752" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "4\n", + "10\n", + "18\n" + ] + } + ], + "source": [ + "for value in f_x:\n", + " print(value)\n", + " if value > 10:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_G5eWGYGmYMp" + }, + "source": [ + "#### Функция `cycle()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "_kC3VssumbF5", + "outputId": "7aea461d-18b5-4454-9837-86f65c7280a0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n", + "1\n", + "2\n" + ] + } + ], + "source": [ + "list_1: list[int] = [1, 2, 3]\n", + "iterator_d = cycle(list_1)\n", + "\n", + "limit = 5\n", + "for item_2 in iterator_d:\n", + " print(item_2)\n", + " limit -= 1\n", + " if limit == 0:\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-IqqesXxrT9M", + "outputId": "8877b29b-24f7-4a4a-eaae-c24bc64786ef" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "P\n", + "y\n", + "t\n", + "h\n", + "o\n", + "n\n", + "P\n", + "y\n", + "t\n", + "h\n" + ] + } + ], + "source": [ + "string = \"Python\"\n", + "iterator_e = cycle(string)\n", + "\n", + "limit = 10\n", + "for item_3 in iterator_e:\n", + " print(item_3)\n", + " limit -= 1\n", + " if limit == 0:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ih5bXVq9sGh6" + }, + "source": [ + "#### Функция `chain()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "EzUlrbwZrmG4", + "outputId": "86f0b35e-e9dc-4749-d987-f02b86d88485" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "iterator_f = chain([\"abc\", \"d\", \"e\", \"f\"], \"abc\", [1, 2, 3])\n", + "print(iterator_f)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Uzij2-C2ttuk", + "outputId": "6895d222-7929-47f6-c8b1-0891648b34ac" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['abc', 'd', 'e', 'f', 'a', 'b', 'c', 1, 2, 3]" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(list(iterator))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "exjJKXZjvZJb", + "outputId": "7c677fcf-7cad-45b4-b4c6-6e61ff8d15f2" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['a', 'b', 'c', 'd', 'e', 'f']" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(list(chain.from_iterable([\"abc\", \"def\"])))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qE3YDv6SufLi", + "outputId": "9e2037bc-b04e-4cf2-d8ba-9b9d7e045ce7" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "45" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result_1 = sum(chain.from_iterable([[1, 2, 3], [4, 5, 6], [7, 8, 9]]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HApgWQJPyGPa" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/python/makarov/chapter_15_iterators.py b/python/makarov/chapter_15_iterators.py new file mode 100644 index 00000000..853f52c7 --- /dev/null +++ b/python/makarov/chapter_15_iterators.py @@ -0,0 +1,329 @@ +"""Макаров. + +Итераторы и генераторы. +""" + +# ## Итераторы и генераторы + +# ### Итерируемый объект и итератор + +# #### Основные определения + +# + +from collections.abc import Iterator +from itertools import chain, count, cycle +from typing import Generator + +for index in [1, 2, 3]: + print(index) +# - + +# встроенная функция iter() вызывает метод .__iter__(), +# создающий итератор +iterator1 = iter([1, 2, 3]) + +# + +iterable_object: list[int] = [1, 2, 3] + +iterator = iter(iterable_object) +print(iterator) +print() + +print(next(iterator)) +print(next(iterator)) +print(next(iterator)) +# - + +for iterator2 in iterable_object: + print(iterator2) + +# + +iterator_a = iter(iterable_object) +iterator_b = iter(iterable_object) + +print(f"A: {next(iterator_a)}") +print(f"A: {next(iterator_a)}") +print(f"A: {next(iterator_a)}") +print(f"B: {next(iterator_b)}") +# - + +iterable_object + +# + +# print(f'A: {next(iterator_a)}') +# - + +print(list(iterator_a), list(iterator_b)) + +for item_s in {1, 1, 2, 3}: # pylint: disable=C0208,W0130 + print(item_s) + +# #### Отсутствие "обратного хода" + +# + +iterator_c = iter(iterable_object) + +for item_c_1 in iterator_c: + print(item_c_1) + break + +for item_c_2 in iterator_c: + print(item_c_2) +# - + +# #### Функция `zip()` + +iterator_tuple = zip(iterable_object, iterable_object) +print(iterator_tuple) + +print(next(iterator_tuple)) +print(next(iterator_tuple)) +print(next(iterator_tuple)) + +for item_z in zip(iterable_object, iterable_object): + print(item_z) + + +# #### Примеры итераторов + +# Возведение в квадрат + +class Square: + """Итератор, возводящий в квадрат числа из переданной последовательности.""" + + def __init__(self, seq: list[int]) -> None: + """Инициализация итератора.""" + self._seq = seq + self._idx = 0 + + def __iter__(self) -> "Square": + """Возвращает сам объект как итератор.""" + return self + + def __next__(self) -> int: + """Возвращает следующее значение итератора.""" + if self._idx < len(self._seq): + square = self._seq[self._idx] ** 2 + self._idx += 1 + return square + + raise StopIteration + + +square_1 = Square([1, 2, 3, 4, 5]) +print(square_1) + +for num_square in square_1: + print(num_square) + + +# Счетчик + +class Counter: + """Итератор, генерирующий последовательность целых чисел в заданном диапазоне.""" + + def __init__(self, start: int = 3, stop: int = 9) -> None: + """Инициализирует итератор с заданными границами диапазона.""" + self._current = start - 1 + self._stop = stop + + def __iter__(self) -> "Counter": + """Возвращает сам объект как итератор.""" + return self + + def __next__(self) -> int: + """Возвращает следующее значение в последовательности.""" + self._current += 1 + if self._current < self._stop: + return self._current + + raise StopIteration + + +counter = Counter() +print(counter) + +print(next(counter)) +print(next(counter)) + +for current_count in counter: + print(current_count) + + +# Класс Iterator модуля collections.abc + +class Counter2(Iterator[int]): + """Итератор. + + Генерирует последовательность целых чисел в заданном диапазоне. + """ + + def __init__(self, start: int = 3, stop: int = 9) -> None: + """Инициализирует итератор с заданными границами диапазона.""" + self._current = start - 1 + self._stop = stop + + def __next__(self) -> int: + """Возвращает следующее значение в последовательности.""" + self._current += 1 + if self._current < self._stop: + return self._current + + raise StopIteration + + +for current_count in Counter2(): + print(current_count) + + +# Бесконечный итератор + +class FibIterator: + """Бесконечный Итератор. + + Генерирует последовательность целых чисел, начиная с 0. + """ + + def __init__(self) -> None: + """Инициализирует итератор.""" + self._idx = 0 + self._current = 0 + self._next = 1 + + def __iter__(self) -> "FibIterator": + """Возвращает сам объект как итератор.""" + return self + + def __next__(self) -> int: + """Возвращает следующее значение в последовательности.""" + self._idx += 1 + self._current, self._next = (self._next, self._current + self._next) + return self._current + + +# + +limit = 10 + +for item_f in FibIterator(): + print(item_f) + limit -= 1 + if limit == 0: + break + + +# - + +# ### Генератор + +# #### Простой пример + +def sequence(end: int) -> list[int]: + """Возвращает список целых чисел от 1 до n включительно.""" + res = [num for num in range(1, end + 1)] + return res + + +print(sequence(5)) + + +def sequence_gen(num_arg: int) -> Generator[int, None, None]: + """Генератор, возвращающий целые числа от 1 до n включительно.""" + yield from range(1, num_arg + 1) + + +print(sequence_gen(5)) + +# + +seq_5 = sequence_gen(5) + +print(next(seq_5)) +print(next(seq_5)) +# - + +for item_s in seq_5: + print(item_s) + +# + +# next(seq_5) +# - + +# #### Generator comprehension + +print(num for num in range(1, 5 + 1)) + +print(list(num for num in range(1, 5 + 1))) + +print(sum(num for num in range(1, 5 + 1))) + +print(5 in (num for num in range(1, 5 + 1))) + +# ### Модуль itertools + +# #### Функция `count()` + +# + +natural_numbers = count(start=1, step=0.5) + +for num in natural_numbers: + print(num) + if num == 2: + break +# - + +list_: list[str] = ["A", "B", "C", "D"] +for item_1 in zip(count(), list_): + print(item_1) + + +# + +def quadratic_poly(num_arg: int) -> int: + """Вычисляет значение квадратичной функции f(x) = x² + x - 2.""" + return num_arg**2 + num_arg - 2 + + +f_x = map(quadratic_poly, count()) +next(f_x) +# - + +for value in f_x: + print(value) + if value > 10: + break + +# #### Функция `cycle()` + +# + +list_1: list[int] = [1, 2, 3] +iterator_d = cycle(list_1) + +limit = 5 +for item_2 in iterator_d: + print(item_2) + limit -= 1 + if limit == 0: + break + +# + +string = "Python" +iterator_e = cycle(string) + +limit = 10 +for item_3 in iterator_e: + print(item_3) + limit -= 1 + if limit == 0: + break +# - + +# #### Функция `chain()` + +iterator_f = chain(["abc", "d", "e", "f"], "abc", [1, 2, 3]) +print(iterator_f) + +print(list(iterator)) + +print(list(chain.from_iterable(["abc", "def"]))) + +result_1 = sum(chain.from_iterable([[1, 2, 3], [4, 5, 6], [7, 8, 9]])) + + diff --git a/python/makarov/chapter_16_decorators.ipynb b/python/makarov/chapter_16_decorators.ipynb new file mode 100644 index 00000000..8addcad2 --- /dev/null +++ b/python/makarov/chapter_16_decorators.ipynb @@ -0,0 +1,2068 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"Макаров.\n", + "\n", + "Декораторы.\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uj3W4pZ3dgXv" + }, + "source": [ + "# Декораторы" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "UWUu0aaT-u4B" + }, + "source": [ + "### Объекты первого класса" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IXifYlrj_YbX" + }, + "source": [ + "Присвоение функции переменной" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ahhHl0zTdfxX" + }, + "outputs": [], + "source": [ + "import functools\n", + "import time\n", + "from typing import Callable, ParamSpec, TypeVar\n", + "\n", + "# ParamSpec - это переменная типа для сигнатуры функции: она «запоминает»\n", + "# все аргументы (позиционные и именованные) функции,\n", + "# чтобы их можно было точно передать дальше с сохранением типобезопасности.\n", + "# Основное применение - функции высшего порядка (в отм числе декораторы)\n", + "Params = ParamSpec(\"Params\")\n", + "\n", + "# TypeVar - это переменная типа, которая позволяет писать обобщённые (generic)\n", + "# функции и классы, сохраняя связь между входными и выходными типами.\n", + "Return = TypeVar(\"Return\")\n", + "\n", + "# объявим функцию\n", + "\n", + "\n", + "def say_hello(name: str) -> None:\n", + " \"\"\"Выводит приветствие.\"\"\"\n", + " print(f\"Привет, {name}!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VKrmngnh-xqg", + "outputId": "43f26846-32a2-4a7c-ab74-ac3066ddbd57" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Привет, Алексей!\n" + ] + } + ], + "source": [ + "# присвоим эту функцию переменной (без скобок)\n", + "say_hello_function = say_hello\n", + "# вызовем функцию из новой переменной\n", + "say_hello_function(\"Алексей\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "INxKkQT__c41" + }, + "source": [ + "Передача функции в качестве аргумента другой функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YEwkUtPu_Iaf" + }, + "outputs": [], + "source": [ + "def simple_calculator(\n", + " operation: Callable[[int, int], int | float], a_arg: int, b_arg: int\n", + ") -> int | float:\n", + " \"\"\"Функция обертка.\n", + "\n", + " Вызывает переданную функцию с переданными аргументами.\n", + " \"\"\"\n", + " return operation(a_arg, b_arg)\n", + "\n", + "\n", + "def add(a_arg: int, b_arg: int) -> int:\n", + " \"\"\"Возвращает сумму двух аргументов.\"\"\"\n", + " return a_arg + b_arg\n", + "\n", + "\n", + "def subtract(a_arg: int, b_arg: int) -> int:\n", + " \"\"\"Возвращает разность двух аргументов.\"\"\"\n", + " return a_arg - b_arg\n", + "\n", + "\n", + "def multiply(a_arg: int, b_arg: int) -> int:\n", + " \"\"\"Возвращает произведение двух аргументов.\"\"\"\n", + " return a_arg * b_arg\n", + "\n", + "\n", + "def divide(a_arg: int, b_arg: int) -> float:\n", + " \"\"\"Возвращает частное от деления первого аргумента на второй аргумент.\"\"\"\n", + " return a_arg / b_arg" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "C0tKH9zgACpY", + "outputId": "73672462-f6be-4036-f019-628a3d0e23c0" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.3333333333333333" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "simple_calculator(divide, 1, 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jU0WfJWIN-cs" + }, + "source": [ + "### Внутренние функции" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uOl-kzspPzwv" + }, + "source": [ + "Вызов внутренней функции" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "wom-NUQnOZYs" + }, + "outputs": [], + "source": [ + "def outer() -> None:\n", + " \"\"\"Внешняя функция.\"\"\"\n", + " print(\"Вызов внешней функции.\")\n", + "\n", + " # обратите внимание, мы объявляем, а затем\n", + " def inner() -> None:\n", + " \"\"\"Внутренняя функция.\"\"\"\n", + " print(\"Вызов внутренней функции.\")\n", + "\n", + " # вызываем внутреннюю функцию\n", + " inner()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "EG7HyDpGOpqF", + "outputId": "7afd2d51-8199-4eb9-8a4c-27afe15b655d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Вызов внешней функции.\n", + "Вызов внутренней функции.\n" + ] + } + ], + "source": [ + "outer()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "lq8mXyyFPmNi" + }, + "outputs": [], + "source": [ + "# inner()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ggx5eY1BP2E_" + }, + "source": [ + "Возвращение функции из функции и замыкание" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "f92IsJmiAGEm" + }, + "outputs": [], + "source": [ + "def create_multiplier(factor: int) -> Callable[[int], int]:\n", + " \"\"\"Создает функцию-умножитель.\"\"\"\n", + "\n", + " def multiplier(number: int) -> int:\n", + " return number * factor\n", + "\n", + " return multiplier" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RKJh1YXZPfvy" + }, + "outputs": [], + "source": [ + "double = create_multiplier(factor=2)\n", + "triple = create_multiplier(factor=3)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 103 + }, + "id": "n3gfeRpjQJv7", + "outputId": "cf19c87f-2159-40cb-93a8-476f8954e477" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ".multiplier at 0x000002DBFA7B39C0>\n" + ] + } + ], + "source": [ + "print(double)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8e_BM_ZbPSrL", + "outputId": "e2e72c8d-1599-4a9b-8c9a-895845021852" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(4, 6)" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(double(2), triple(2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "iiyiBcU8dAqM" + }, + "outputs": [], + "source": [ + "def create_multiplier_1(factor: int) -> Callable[[int], int]:\n", + " \"\"\"Создает функцию-умножитель.\"\"\"\n", + " return lambda number: factor * number" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VuEd1WLtdMVY", + "outputId": "779967db-9a33-42e6-9f29-1f9b57b098a6" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "triple_1 = create_multiplier_1(factor=3)\n", + "triple_1(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jOxX3byTQcvZ" + }, + "source": [ + "### Знакомство с декораторами" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fl2py8bY_MGw" + }, + "source": [ + "Простой декоратор" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DqWzDydyPdS6" + }, + "outputs": [], + "source": [ + "def simple_decorator(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, Return]:\n", + " \"\"\"Простой декоратор.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " print(\"Текст до вызова функции func().\")\n", + " result = func(*args, **kwargs)\n", + " print(\"Текст после вызова функции func().\")\n", + "\n", + " return result\n", + "\n", + " return wrapper\n", + "\n", + "\n", + "def say_hello_1() -> None:\n", + " \"\"\"Функция-приветствие.\"\"\"\n", + " print(\"Привет!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YeZqM0Ri-0cE" + }, + "outputs": [], + "source": [ + "say_hello_var = simple_decorator(say_hello_1)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bRD44QdeTtbL", + "outputId": "26d50e1d-8dac-422f-a4b1-7250cd64f8c3" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Текст до вызова функции func().\n", + "Привет!\n", + "Текст после вызова функции func().\n" + ] + } + ], + "source": [ + "say_hello_var()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3_n1GHNRDn-u" + }, + "source": [ + "Конструкция @decorator" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "aPTsoheWUyqO" + }, + "outputs": [], + "source": [ + "@simple_decorator\n", + "def say_hi() -> None:\n", + " \"\"\"Функция повторного приветствия.\"\"\"\n", + " print(\"Снова, привет!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8FRvX4NEUl6T", + "outputId": "85a01dca-c68d-41b9-ea86-a489a8d45d50" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Текст до вызова функции func().\n", + "Снова, привет!\n", + "Текст после вызова функции func().\n" + ] + } + ], + "source": [ + "say_hi()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JaGa8Qwr_N-5" + }, + "source": [ + "Функции с аргументами" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fKHekNgUHFLo" + }, + "outputs": [], + "source": [ + "@simple_decorator\n", + "def say_hello_with_name(name_arg: str) -> None:\n", + " \"\"\"Приветствие с именем.\"\"\"\n", + " print(f\"Привет, {name_arg}!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EeW8G0LsHPJu" + }, + "outputs": [], + "source": [ + "# say_hello_with_name('Алексей')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WLoje-LpU_tJ" + }, + "outputs": [], + "source": [ + "def decorator_with_name_argument(\n", + " func: Callable[[str], None],\n", + ") -> Callable[[str], None]:\n", + " \"\"\"Декоратор, принимающий имя.\"\"\"\n", + "\n", + " def wrapper(name: str) -> None:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " print(\"Текст до вызова функции func().\")\n", + " func(name)\n", + " print(\"Текст после вызова функции func().\")\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HcQaW7IAVm5Q" + }, + "outputs": [], + "source": [ + "@decorator_with_name_argument\n", + "def say_hello_with_name_1(name: str) -> None:\n", + " \"\"\"Приветствие с именем.\"\"\"\n", + " print(f\"Привет, {name}!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Ps96hpvjV9Ra", + "outputId": "95ea1054-a1e0-49ee-cc9b-a93fa8075804" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Текст до вызова функции func().\n", + "Привет, Алексей!\n", + "Текст после вызова функции func().\n" + ] + } + ], + "source": [ + "say_hello_with_name_1(\"Алексей\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "XLO10uz8jTgf" + }, + "outputs": [], + "source": [ + "def decorator_with_arguments(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, Return]:\n", + " \"\"\"Декоратор с аргументами.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " print(\"Текст до вызова функции func().\")\n", + "\n", + " result = func(*args, **kwargs)\n", + "\n", + " print(\"Текст после вызова функции func().\")\n", + "\n", + " return result\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mmkQw_NeQgDo" + }, + "outputs": [], + "source": [ + "@decorator_with_arguments\n", + "def say_hello_with_argument(name: str) -> None:\n", + " \"\"\"Функция-приветствие, принимающая имя.\"\"\"\n", + " print(f\"Привет, {name}!\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "6an3iiFLQjhx", + "outputId": "709e6c14-596e-4feb-ffd3-f8c3d0ef796f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Текст до вызова функции func().\n", + "Привет, Алексей!\n", + "Текст после вызова функции func().\n" + ] + } + ], + "source": [ + "say_hello_with_argument(\"Алексей\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nYfQs9qTTvpx" + }, + "source": [ + "Возвращение значения декорируемой функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "n3O_bUeDcd6H" + }, + "outputs": [], + "source": [ + "def another_decorator(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, Return]:\n", + " \"\"\"Другой декоратор с аргументами.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " print(\"Текст внутренней функции.\")\n", + "\n", + " return func(*args, **kwargs)\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0QfyEIQ0Tyo1" + }, + "outputs": [], + "source": [ + "@another_decorator\n", + "def return_name_1(name: str) -> str:\n", + " \"\"\"Возвращает переданное имя.\"\"\"\n", + " return name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Odulil-rT_6L", + "outputId": "c87fc41e-03c5-4af8-d8eb-4cc98e3a7db3" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Текст внутренней функции.\n" + ] + } + ], + "source": [ + "returned_value = return_name_1(\"Алексей\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Z4mn1aNqUItV", + "outputId": "c86cc40d-161b-4196-8fa5-640d6ad05008" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "print(returned_value)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vY4KoCEpUWPF" + }, + "outputs": [], + "source": [ + "def another_decorator_1(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, Return]:\n", + " \"\"\"Другой декоратор.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " print(\"Текст внутренней функции.\")\n", + " return func(*args, **kwargs) # внутренняя функция возвращает func()\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pdBi1JIgUfbA" + }, + "outputs": [], + "source": [ + "@another_decorator_1\n", + "def return_name(name_arg: str) -> str:\n", + " \"\"\"Возвращает переданное имя.\"\"\"\n", + " return name_arg" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DgmF5Y80UhxE", + "outputId": "fe7a2730-8dec-4c6e-9cba-3b6e16a71c04" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Текст внутренней функции.\n" + ] + } + ], + "source": [ + "returned_value = return_name(\"Алексей\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "C2pBMz0WcDdL", + "outputId": "76d1d18f-d81e-49c9-eecc-9bcfddcf88ff" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Алексей\n" + ] + } + ], + "source": [ + "print(returned_value)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "96f9wVE9V9Vr" + }, + "source": [ + "Декоратор @functools.wraps" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "MdPnhLh7UjM8" + }, + "outputs": [], + "source": [ + "def square(num: int) -> int:\n", + " \"\"\"Squares a number.\"\"\"\n", + " return num * num" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "V4UwZvebVvGN", + "outputId": "2fd308ec-95f3-4dad-e197-8c77a432f69c" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('square', 'Squares a number')" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(square.__name__, square.__doc__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0iKP_IpEWNnn" + }, + "outputs": [], + "source": [ + "def repeat_twice(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, None]:\n", + " \"\"\"Декоратор, который дважды вызывает функция.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " func(*args, **kwargs)\n", + " func(*args, **kwargs)\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "XQPua1yJVwWl" + }, + "outputs": [], + "source": [ + "@repeat_twice\n", + "def square_1(num: int) -> int:\n", + " \"\"\"Squares a number.\"\"\"\n", + " result = num * num\n", + "\n", + " print(result)\n", + "\n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "Xp1b9jLebCpC" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9\n", + "9\n" + ] + } + ], + "source": [ + "square_1(3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "g5Ijk3fvXDtD", + "outputId": "c0680c69-21fa-47c6-c89d-22c5083f7a2b" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('wrapper', None)" + ] + }, + "execution_count": 85, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "square.__name__, square.__doc__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TlJNvigxXMZE" + }, + "outputs": [], + "source": [ + "def repeat_twice_1(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, None]:\n", + " \"\"\"Декоратор, который дважды вызывает функция.\"\"\"\n", + "\n", + " @functools.wraps(func)\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " func(*args, **kwargs)\n", + " func(*args, **kwargs)\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "id": "DpxKd94oXQlA" + }, + "outputs": [], + "source": [ + "@repeat_twice_1\n", + "def square_2(num: int) -> int:\n", + " \"\"\"Squares a number.\"\"\"\n", + " result = num * num\n", + "\n", + " print(result)\n", + "\n", + " return result" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YsaelJl3YVA0", + "outputId": "9e453de0-6370-41d4-ac20-1d060b0592f3" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "square_2 Squares a number.\n" + ] + } + ], + "source": [ + "print(square_2.__name__, square_2.__doc__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 103 + }, + "id": "Wvl0I71Oh4dc", + "outputId": "3ce27822-0bbe-4008-f36e-3d5a9d9807db" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "print(square_2.__wrapped__) # type: ignore" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tNFRtACYf2Ik" + }, + "outputs": [], + "source": [ + "def repeat_twice_2(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, None]:\n", + " \"\"\"Декоратор, который дважды вызывает функция.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " func(*args, **kwargs)\n", + " func(*args, **kwargs)\n", + " functools.update_wrapper(wrapper, func)\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OqtPbkS0f-Ox" + }, + "outputs": [], + "source": [ + "@repeat_twice_2\n", + "def power(num: int, pow_arg: int) -> None:\n", + " \"\"\"Raise to a power.\"\"\"\n", + " print(num**pow_arg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cUOkkwwdgFHh", + "outputId": "898e551c-b7bc-4f4f-a647-5342b1d174f5" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n", + "8\n" + ] + } + ], + "source": [ + "power(2, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 37 + }, + "id": "HZvDG-hRgHbZ", + "outputId": "258e9681-6bac-4d0f-c4bd-7f639e2ff18b" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Raises to a power'" + ] + }, + "execution_count": 93, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(power.__doc__)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DRNFII11hPme" + }, + "source": [ + "### Примеры декораторов" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "90ciKrTXhR4y" + }, + "source": [ + "Создание логов" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "PjrkD7rTgQZh" + }, + "outputs": [], + "source": [ + "def logging(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, Return]:\n", + " \"\"\"Логирование вызовов функции.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " print(f\"Calling {func.__name__} with args: {args}, kwargs: {kwargs}\")\n", + "\n", + " result = func(*args, **kwargs)\n", + "\n", + " print(f\"{func.__name__} returned: {result}\")\n", + "\n", + " return result\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "q5a47uz5iDcE", + "outputId": "f98c0fa3-3b97-4247-a5ae-cbc0da48e92a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calling power_1 with args: (5, 3), kwargs: {}\n", + "power_1 returned: 125\n" + ] + }, + { + "data": { + "text/plain": [ + "125" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@logging\n", + "def power_1(num: int, pow_arg: int) -> int:\n", + " \"\"\"Raise to a power.\"\"\"\n", + " return int(num**pow_arg)\n", + "\n", + "\n", + "power_1(5, 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BATiTOZch5Hd" + }, + "source": [ + "Время исполнения функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JzUr3gBrhgsg" + }, + "outputs": [], + "source": [ + "def timer(\n", + " func: Callable[Params, Return],\n", + ") -> Callable[Params, Return]:\n", + " \"\"\"Декоратор для вычисления времени выполнения функции.\"\"\"\n", + "\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " start_time = time.time()\n", + "\n", + " result = func(*args, **kwargs)\n", + "\n", + " end_time = time.time()\n", + "\n", + " print(f\"{func.__name__} executed in {end_time - start_time:.4f} seconds\")\n", + "\n", + " return result\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 55 + }, + "id": "MvgB0y7IiKEJ", + "outputId": "35bdcec2-a698-40c0-8357-d49bf741c4fb" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "delayed_function executed in 2.0012 seconds\n" + ] + }, + { + "data": { + "text/plain": [ + "'execution completed'" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@timer\n", + "def delayed_function(delay: int) -> str:\n", + " \"\"\"Функция с задержкой выполнения.\"\"\"\n", + " time.sleep(delay)\n", + " return \"execution completed\"\n", + "\n", + "\n", + "delayed_function(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Far9nIP_lBcV" + }, + "source": [ + "### Типы методов" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yiBHRhX0mr1X" + }, + "source": [ + "Методы экземпляра" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uMswH5MoiBQg" + }, + "outputs": [], + "source": [ + "class CatClass:\n", + " \"\"\"Класс кот.\"\"\"\n", + "\n", + " def __init__(self, color: str) -> None:\n", + " \"\"\"Инициализация кота с цветом.\"\"\"\n", + " self.color = color\n", + " self.type_ = \"cat\"\n", + "\n", + " def info(self) -> None:\n", + " \"\"\"Вывод информации о коте.\"\"\"\n", + " print(self.color, self.type_, sep=\", \")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ORHkpRULnV48", + "outputId": "5fab4183-8729-4a02-8996-a35b50a330fd" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "black, cat\n" + ] + } + ], + "source": [ + "cat = CatClass(color=\"black\")\n", + "cat.info()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VUKAK7pIO0OU" + }, + "outputs": [], + "source": [ + "# CatClass.info()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mXPMkHLjQn_i" + }, + "outputs": [], + "source": [ + "# CatClass.color" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ny5x6rT7o3sN" + }, + "source": [ + "Методы класса" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": { + "id": "CIn4oi0TniKB" + }, + "outputs": [], + "source": [ + "class CatClass1:\n", + " \"\"\"Класс кот.\"\"\"\n", + "\n", + " species = \"кошка\" # переменная класса доступна всем экземплярам\n", + "\n", + " def __init__(self, color: str) -> None:\n", + " \"\"\"Инициализация кота с цветом.\"\"\"\n", + " self.color = color\n", + "\n", + " def info(self) -> None:\n", + " \"\"\"Вывод информации о коте.\"\"\"\n", + " print(self.color)\n", + "\n", + " @classmethod\n", + " def get_species(cls) -> None:\n", + " \"\"\"Вывод значения аттрибута класса species.\"\"\"\n", + " print(cls.species)\n", + " # нет доступа к переменным color и type_" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 37 + }, + "id": "OeiyzIrgoJnW", + "outputId": "f7cd1440-f237-4aa4-cff6-e2d35fa3be4d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'кошка'" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(CatClass1.species)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qq-lk-R1nInf", + "outputId": "764649e5-7dcb-4178-c46c-b11d81724efe" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "кошка\n" + ] + } + ], + "source": [ + "CatClass1.get_species()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ksfgajzZo9wu" + }, + "source": [ + "Статические методы" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JuPIH3Z7o0n2" + }, + "outputs": [], + "source": [ + "class CatClass2:\n", + " \"\"\"Класс кот.\"\"\"\n", + "\n", + " species = \"кошка\"\n", + "\n", + " def __init__(self, color: str) -> None:\n", + " \"\"\"Инициализация кота с цветом.\"\"\"\n", + " self.color = color\n", + " self.type_ = \"cat\"\n", + "\n", + " def info(self) -> None:\n", + " \"\"\"Вывод информации о коте.\"\"\"\n", + " print(self.color, self.type_)\n", + "\n", + " @classmethod\n", + " def get_species(cls) -> None:\n", + " \"\"\"Вывод значения аттрибута класса species.\"\"\"\n", + " print(cls.species)\n", + " # нет доступа к переменным color и type_\n", + "\n", + " @staticmethod\n", + " def convert_to_pounds(kg: int) -> None:\n", + " \"\"\"Конвертирует килограммы в фунты.\"\"\"\n", + " print(f\"{kg} kg is approximately {kg * 2.205} pounds\")\n", + " # нет доступа к переменным species, color и type_" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bfz6Wubqp-AO", + "outputId": "d42fac14-e6b5-4be2-ab69-66b1e7e7c049" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4 kg is approximately 8.82 pounds\n" + ] + } + ], + "source": [ + "CatClass2.convert_to_pounds(4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DaLLVoiEqEQF", + "outputId": "486cda8c-a04f-4e3c-db24-13281f3cee9e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 kg is approximately 11.025 pounds\n" + ] + } + ], + "source": [ + "cat2 = CatClass2(\"gray\")\n", + "cat2.convert_to_pounds(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xy2HkzH6ZrRG" + }, + "source": [ + "### Декорирование класса" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zKj05Fh06Sm_" + }, + "source": [ + "Декорирование методов" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": { + "id": "G9MuM7PCZs8-" + }, + "outputs": [], + "source": [ + "class CatClass3:\n", + " \"\"\"Класс кот.\"\"\"\n", + "\n", + " @logging\n", + " def __init__(self, color: str) -> None:\n", + " \"\"\"Инициализация кота с цветом.\"\"\"\n", + " self.color = color\n", + " self.type_ = \"cat\"\n", + "\n", + " @timer\n", + " def info(self) -> None:\n", + " \"\"\"Вывод информации о коте.\"\"\"\n", + " time.sleep(2)\n", + " print(self.color, self.type_, sep=\", \")" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3fiHjwEJ4cTV", + "outputId": "cd8d8c29-666c-44c3-a103-087093a1db83" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calling __init__ with args: (<__main__.CatClass3 object at 0x000002DBFA7C5550>, 'black'), kwargs: {}\n", + "__init__ returned: None\n" + ] + } + ], + "source": [ + "cat3 = CatClass3(\"black\")" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Kt7-LubB4y6g", + "outputId": "ee6e78e7-6269-4b3d-8a7b-075938562c9d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "black, cat\n", + "info executed in 2.0005 seconds\n" + ] + } + ], + "source": [ + "cat3.info()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "epmndsSc6Uvh" + }, + "source": [ + "Декорирование всего класса" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "id": "0cXQX0004174" + }, + "outputs": [], + "source": [ + "@timer\n", + "class CatClass4:\n", + " \"\"\"Класс кот.\"\"\"\n", + "\n", + " def __init__(self, color: str) -> None:\n", + " \"\"\"Инициализация кота с цветом.\"\"\"\n", + " self.color = color\n", + " self.type_ = \"cat\"\n", + "\n", + " def info(self) -> None:\n", + " \"\"\"Вывод информации о коте.\"\"\"\n", + " time.sleep(2)\n", + " print(self.color, self.type_, sep=\", \")" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "P6aIA7_a6gZh", + "outputId": "c40ae050-d7dc-4488-a3ec-cfdf93be806b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CatClass4 executed in 0.0000 seconds\n" + ] + } + ], + "source": [ + "cat4 = CatClass4(\"gray\")" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-HqSIPFG6jo2", + "outputId": "bc78ba12-4f6c-4a8f-9499-96b6feb5a561" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "gray, cat\n" + ] + } + ], + "source": [ + "cat4.info()" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "id": "wN17-w_s7WI7" + }, + "outputs": [], + "source": [ + "setattr(cat4, \"weight\", 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "w-3c9Vny7d4f", + "outputId": "81981202-4e38-491b-8078-1100747bf04b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5 5\n" + ] + } + ], + "source": [ + "print(\n", + " cat4.weight, # type: ignore # pylint: disable=E1101\n", + " getattr(cat4, \"weight\"),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "suehA7UO6ldC" + }, + "outputs": [], + "source": [ + "# TypeVar - это переменная типа, которая позволяет писать обобщённые (generic)\n", + "# функции и классы, сохраняя связь между входными и выходными типами.\n", + "Class = TypeVar(\"Class\", bound=type)\n", + "\n", + "\n", + "def add_attribute(\n", + " attribute_name: str, attribute_value: str\n", + ") -> Callable[[Class], Class]:\n", + " \"\"\"Декоратор класса, добавляющий указанный атрибут к классу.\"\"\"\n", + "\n", + " def wrapper(cls: Class) -> Class:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " setattr(cls, attribute_name, attribute_value)\n", + " return cls\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "id": "ra4O3lsm62RO" + }, + "outputs": [], + "source": [ + "@add_attribute(\"species\", \"кошка\")\n", + "class CatClass5:\n", + " \"\"\"Класс кот.\"\"\"\n", + "\n", + " def __init__(self, color: str) -> None:\n", + " \"\"\"Инициализация кота с цветом.\"\"\"\n", + " self.color = color\n", + " self.type_ = \"cat\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 37 + }, + "id": "VRPuN3Wk75y4", + "outputId": "201d5a8f-811b-4812-e834-2874b53ccd8d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "кошка\n" + ] + } + ], + "source": [ + "print(CatClass5.species) # type: ignore # pylint: disable=E1101" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "D9EuxH7p8Tcz" + }, + "source": [ + "### Несколько декораторов" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NqYf_Co077ii" + }, + "outputs": [], + "source": [ + "@logging\n", + "@timer\n", + "def delayed_function_1(delay: int) -> str:\n", + " \"\"\"Функция с задержкой выполнения.\"\"\"\n", + " time.sleep(delay)\n", + " return \"execution completed\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 91 + }, + "id": "Px_2Rz_Z8goN", + "outputId": "7f998623-0dd3-4a0f-e8dd-27eab7506d4a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calling wrapper with args: (2,), kwargs: {}\n", + "delayed_function executed in 2.0001 seconds\n", + "wrapper returned: execution completed\n" + ] + }, + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'execution completed'" + ] + }, + "execution_count": 120, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "delayed_function_1(2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6vA85Et4Gs4v" + }, + "outputs": [], + "source": [ + "# не забудем заново объявить функцию без декораторов\n", + "\n", + "\n", + "def delayed_function_3(delay: int) -> str:\n", + " \"\"\"Функция с задержкой выполнения.\"\"\"\n", + " time.sleep(delay)\n", + " return \"execution completed\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 91 + }, + "id": "oBdmnqV18ifq", + "outputId": "91a5a86a-5090-49ae-8476-8c7c6b4bf981" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calling wrapper with args: (2,), kwargs: {}\n", + "delayed_function executed in 2.0001 seconds\n", + "wrapper returned: execution completed\n" + ] + }, + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'execution completed'" + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "delayed_function_4 = logging(timer(delayed_function))\n", + "delayed_function_4(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "drHaoUEXEPfP" + }, + "source": [ + "### Декораторы с аргументами" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wrew14E2Fm2L" + }, + "outputs": [], + "source": [ + "def repeat(\n", + " n_times: int,\n", + ") -> Callable[[Callable[Params, Return]], Callable[Params, None]]:\n", + " \"\"\"Декоратор, вызывающий функцию указанное количество раз.\"\"\"\n", + "\n", + " def inner_decorator(\n", + " func: Callable[Params, Return],\n", + " ) -> Callable[Params, None]:\n", + " \"\"\"Внутренний декоратор.\"\"\"\n", + "\n", + " @functools.wraps(func)\n", + " def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " for _ in range(n_times):\n", + " func(*args, **kwargs)\n", + "\n", + " return wrapper\n", + "\n", + " return inner_decorator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1KdWR3viIeBk" + }, + "outputs": [], + "source": [ + "@repeat(n_times=3)\n", + "def say_hello_3(name: str) -> None:\n", + " \"\"\"Функция-обертка.\"\"\"\n", + " print(f\"Привет, {name}!\")" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "N2zEUb1IIiJ6", + "outputId": "542eff2e-1641-421f-a208-12a53e98037e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Привет, Алексей!\n", + "Привет, Алексей!\n", + "Привет, Алексей!\n" + ] + } + ], + "source": [ + "say_hello_3(\"Алексей\")" + ] + } + ], + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/python/makarov/chapter_16_decorators.py b/python/makarov/chapter_16_decorators.py new file mode 100644 index 00000000..fdcfaf20 --- /dev/null +++ b/python/makarov/chapter_16_decorators.py @@ -0,0 +1,685 @@ +"""Макаров. + +Декораторы. +""" + +# # Декораторы + +# ### Объекты первого класса + +# Присвоение функции переменной + +# + +import functools +import time +from typing import Callable, ParamSpec, TypeVar + +# ParamSpec - это переменная типа для сигнатуры функции: она «запоминает» +# все аргументы (позиционные и именованные) функции, +# чтобы их можно было точно передать дальше с сохранением типобезопасности. +# Основное применение - функции высшего порядка (в отм числе декораторы) +Params = ParamSpec("Params") + +# TypeVar - это переменная типа, которая позволяет писать обобщённые (generic) +# функции и классы, сохраняя связь между входными и выходными типами. +Return = TypeVar("Return") + +# объявим функцию + + +def say_hello(name: str) -> None: + """Выводит приветствие.""" + print(f"Привет, {name}!") + + +# - + +# присвоим эту функцию переменной (без скобок) +say_hello_function = say_hello +# вызовем функцию из новой переменной +say_hello_function("Алексей") + + +# Передача функции в качестве аргумента другой функции + +# + +def simple_calculator( + operation: Callable[[int, int], int | float], a_arg: int, b_arg: int +) -> int | float: + """Функция обертка. + + Вызывает переданную функцию с переданными аргументами. + """ + return operation(a_arg, b_arg) + + +def add(a_arg: int, b_arg: int) -> int: + """Возвращает сумму двух аргументов.""" + return a_arg + b_arg + + +def subtract(a_arg: int, b_arg: int) -> int: + """Возвращает разность двух аргументов.""" + return a_arg - b_arg + + +def multiply(a_arg: int, b_arg: int) -> int: + """Возвращает произведение двух аргументов.""" + return a_arg * b_arg + + +def divide(a_arg: int, b_arg: int) -> float: + """Возвращает частное от деления первого аргумента на второй аргумент.""" + return a_arg / b_arg + + +# - + +simple_calculator(divide, 1, 3) + + +# ### Внутренние функции + +# Вызов внутренней функции + +def outer() -> None: + """Внешняя функция.""" + print("Вызов внешней функции.") + + # обратите внимание, мы объявляем, а затем + def inner() -> None: + """Внутренняя функция.""" + print("Вызов внутренней функции.") + + # вызываем внутреннюю функцию + inner() + + +outer() + + +# + +# inner() +# - + +# Возвращение функции из функции и замыкание + +def create_multiplier(factor: int) -> Callable[[int], int]: + """Создает функцию-умножитель.""" + + def multiplier(number: int) -> int: + return number * factor + + return multiplier + + +double = create_multiplier(factor=2) +triple = create_multiplier(factor=3) + +print(double) + +print(double(2), triple(2)) + + +def create_multiplier_1(factor: int) -> Callable[[int], int]: + """Создает функцию-умножитель.""" + return lambda number: factor * number + + +triple_1 = create_multiplier_1(factor=3) +triple_1(2) + + +# ### Знакомство с декораторами + +# Простой декоратор + +# + +def simple_decorator( + func: Callable[Params, Return], +) -> Callable[Params, Return]: + """Простой декоратор.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return: + """Функция-обертка.""" + print("Текст до вызова функции func().") + result = func(*args, **kwargs) + print("Текст после вызова функции func().") + + return result + + return wrapper + + +def say_hello_1() -> None: + """Функция-приветствие.""" + print("Привет!") + + +# - + +say_hello_var = simple_decorator(say_hello_1) + +say_hello_var() + + +# Конструкция @decorator + +@simple_decorator +def say_hi() -> None: + """Функция повторного приветствия.""" + print("Снова, привет!") + + +say_hi() + + +# Функции с аргументами + +@simple_decorator +def say_hello_with_name(name_arg: str) -> None: + """Приветствие с именем.""" + print(f"Привет, {name_arg}!") + + +# + +# say_hello_with_name('Алексей') +# - + +def decorator_with_name_argument( + func: Callable[[str], None], +) -> Callable[[str], None]: + """Декоратор, принимающий имя.""" + + def wrapper(name: str) -> None: + """Функция-обертка.""" + print("Текст до вызова функции func().") + func(name) + print("Текст после вызова функции func().") + + return wrapper + + +@decorator_with_name_argument +def say_hello_with_name_1(name: str) -> None: + """Приветствие с именем.""" + print(f"Привет, {name}!") + + +say_hello_with_name_1("Алексей") + + +def decorator_with_arguments( + func: Callable[Params, Return], +) -> Callable[Params, Return]: + """Декоратор с аргументами.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return: + """Функция-обертка.""" + print("Текст до вызова функции func().") + + result = func(*args, **kwargs) + + print("Текст после вызова функции func().") + + return result + + return wrapper + + +@decorator_with_arguments +def say_hello_with_argument(name: str) -> None: + """Функция-приветствие, принимающая имя.""" + print(f"Привет, {name}!") + + +say_hello_with_argument("Алексей") + + +# Возвращение значения декорируемой функции + +def another_decorator( + func: Callable[Params, Return], +) -> Callable[Params, Return]: + """Другой декоратор с аргументами.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return: + """Функция-обертка.""" + print("Текст внутренней функции.") + + return func(*args, **kwargs) + + return wrapper + + +@another_decorator +def return_name_1(name: str) -> str: + """Возвращает переданное имя.""" + return name + + +returned_value = return_name_1("Алексей") + +print(returned_value) + + +def another_decorator_1( + func: Callable[Params, Return], +) -> Callable[Params, Return]: + """Другой декоратор.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return: + """Функция-обертка.""" + print("Текст внутренней функции.") + return func(*args, **kwargs) # внутренняя функция возвращает func() + + return wrapper + + +@another_decorator_1 +def return_name(name_arg: str) -> str: + """Возвращает переданное имя.""" + return name_arg + + +returned_value = return_name("Алексей") + +print(returned_value) + + +# Декоратор @functools.wraps + +def square(num: int) -> int: + """Squares a number.""" + return num * num + + +print(square.__name__, square.__doc__) + + +def repeat_twice( + func: Callable[Params, Return], +) -> Callable[Params, None]: + """Декоратор, который дважды вызывает функция.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None: + """Функция-обертка.""" + func(*args, **kwargs) + func(*args, **kwargs) + + return wrapper + + +@repeat_twice +def square_1(num: int) -> int: + """Squares a number.""" + result = num * num + + print(result) + + return result + + +square_1(3) + +square.__name__, square.__doc__ + + +def repeat_twice_1( + func: Callable[Params, Return], +) -> Callable[Params, None]: + """Декоратор, который дважды вызывает функция.""" + + @functools.wraps(func) + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None: + """Функция-обертка.""" + func(*args, **kwargs) + func(*args, **kwargs) + + return wrapper + + +@repeat_twice_1 +def square_2(num: int) -> int: + """Squares a number.""" + result = num * num + + print(result) + + return result + + +print(square_2.__name__, square_2.__doc__) + +print(square_2.__wrapped__) # type: ignore + + +def repeat_twice_2( + func: Callable[Params, Return], +) -> Callable[Params, None]: + """Декоратор, который дважды вызывает функция.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None: + """Функция-обертка.""" + func(*args, **kwargs) + func(*args, **kwargs) + functools.update_wrapper(wrapper, func) + + return wrapper + + +@repeat_twice_2 +def power(num: int, pow_arg: int) -> None: + """Raise to a power.""" + print(num**pow_arg) + + +power(2, 3) + +print(power.__doc__) + + +# ### Примеры декораторов + +# Создание логов + +def logging( + func: Callable[Params, Return], +) -> Callable[Params, Return]: + """Логирование вызовов функции.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return: + """Функция-обертка.""" + print(f"Calling {func.__name__} with args: {args}, kwargs: {kwargs}") + + result = func(*args, **kwargs) + + print(f"{func.__name__} returned: {result}") + + return result + + return wrapper + + +# + +@logging +def power_1(num: int, pow_arg: int) -> int: + """Raise to a power.""" + return int(num**pow_arg) + + +power_1(5, 3) + + +# - + +# Время исполнения функции + +def timer( + func: Callable[Params, Return], +) -> Callable[Params, Return]: + """Декоратор для вычисления времени выполнения функции.""" + + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> Return: + """Функция-обертка.""" + start_time = time.time() + + result = func(*args, **kwargs) + + end_time = time.time() + + print(f"{func.__name__} executed in {end_time - start_time:.4f} seconds") + + return result + + return wrapper + + +# + +@timer +def delayed_function(delay: int) -> str: + """Функция с задержкой выполнения.""" + time.sleep(delay) + return "execution completed" + + +delayed_function(2) + + +# - + +# ### Типы методов + +# Методы экземпляра + +class CatClass: + """Класс кот.""" + + def __init__(self, color: str) -> None: + """Инициализация кота с цветом.""" + self.color = color + self.type_ = "cat" + + def info(self) -> None: + """Вывод информации о коте.""" + print(self.color, self.type_, sep=", ") + + +cat = CatClass(color="black") +cat.info() + + +# + +# CatClass.info() + +# + +# CatClass.color +# - + +# Методы класса + +class CatClass1: + """Класс кот.""" + + species = "кошка" # переменная класса доступна всем экземплярам + + def __init__(self, color: str) -> None: + """Инициализация кота с цветом.""" + self.color = color + + def info(self) -> None: + """Вывод информации о коте.""" + print(self.color) + + @classmethod + def get_species(cls) -> None: + """Вывод значения аттрибута класса species.""" + print(cls.species) + # нет доступа к переменным color и type_ + + +print(CatClass1.species) + +CatClass1.get_species() + + +# Статические методы + +class CatClass2: + """Класс кот.""" + + species = "кошка" + + def __init__(self, color: str) -> None: + """Инициализация кота с цветом.""" + self.color = color + self.type_ = "cat" + + def info(self) -> None: + """Вывод информации о коте.""" + print(self.color, self.type_) + + @classmethod + def get_species(cls) -> None: + """Вывод значения аттрибута класса species.""" + print(cls.species) + # нет доступа к переменным color и type_ + + @staticmethod + def convert_to_pounds(kg: int) -> None: + """Конвертирует килограммы в фунты.""" + print(f"{kg} kg is approximately {kg * 2.205} pounds") + # нет доступа к переменным species, color и type_ + + +CatClass2.convert_to_pounds(4) + +cat2 = CatClass2("gray") +cat2.convert_to_pounds(5) + + +# ### Декорирование класса + +# Декорирование методов + +class CatClass3: + """Класс кот.""" + + @logging + def __init__(self, color: str) -> None: + """Инициализация кота с цветом.""" + self.color = color + self.type_ = "cat" + + @timer + def info(self) -> None: + """Вывод информации о коте.""" + time.sleep(2) + print(self.color, self.type_, sep=", ") + + +cat3 = CatClass3("black") + +cat3.info() + + +# Декорирование всего класса + +@timer +class CatClass4: + """Класс кот.""" + + def __init__(self, color: str) -> None: + """Инициализация кота с цветом.""" + self.color = color + self.type_ = "cat" + + def info(self) -> None: + """Вывод информации о коте.""" + time.sleep(2) + print(self.color, self.type_, sep=", ") + + +cat4 = CatClass4("gray") + +cat4.info() + +setattr(cat4, "weight", 5) + +print( + cat4.weight, # type: ignore # pylint: disable=E1101 + getattr(cat4, "weight"), +) + +# + +# TypeVar - это переменная типа, которая позволяет писать обобщённые (generic) +# функции и классы, сохраняя связь между входными и выходными типами. +Class = TypeVar("Class", bound=type) + + +def add_attribute( + attribute_name: str, attribute_value: str +) -> Callable[[Class], Class]: + """Декоратор класса, добавляющий указанный атрибут к классу.""" + + def wrapper(cls: Class) -> Class: + """Функция-обертка.""" + setattr(cls, attribute_name, attribute_value) + return cls + + return wrapper + + +# - + +@add_attribute("species", "кошка") +class CatClass5: + """Класс кот.""" + + def __init__(self, color: str) -> None: + """Инициализация кота с цветом.""" + self.color = color + self.type_ = "cat" + + +print(CatClass5.species) # type: ignore # pylint: disable=E1101 + + +# ### Несколько декораторов + +@logging +@timer +def delayed_function_1(delay: int) -> str: + """Функция с задержкой выполнения.""" + time.sleep(delay) + return "execution completed" + + +delayed_function_1(2) + +# + +# не забудем заново объявить функцию без декораторов + + +def delayed_function_3(delay: int) -> str: + """Функция с задержкой выполнения.""" + time.sleep(delay) + return "execution completed" + + +# - + +delayed_function_4 = logging(timer(delayed_function)) +delayed_function_4(2) + + +# ### Декораторы с аргументами + +def repeat( + n_times: int, +) -> Callable[[Callable[Params, Return]], Callable[Params, None]]: + """Декоратор, вызывающий функцию указанное количество раз.""" + + def inner_decorator( + func: Callable[Params, Return], + ) -> Callable[Params, None]: + """Внутренний декоратор.""" + + @functools.wraps(func) + def wrapper(*args: Params.args, **kwargs: Params.kwargs) -> None: + """Функция-обертка.""" + for _ in range(n_times): + func(*args, **kwargs) + + return wrapper + + return inner_decorator + + +@repeat(n_times=3) +def say_hello_3(name: str) -> None: + """Функция-обертка.""" + print(f"Привет, {name}!") + + +say_hello_3("Алексей") diff --git a/python/makarov/chapter_1_var.ipynb b/python/makarov/chapter_1_var.ipynb new file mode 100644 index 00000000..0e6ee354 --- /dev/null +++ b/python/makarov/chapter_1_var.ipynb @@ -0,0 +1,492 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 47, + "id": "c7513743", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Глава 1. Переменные в Питоне.'" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Глава 1. Переменные в Питоне.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "e6c64949", + "metadata": {}, + "source": [ + "### Как объявить переменную в Питоне" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "a684a600", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "15\n" + ] + } + ], + "source": [ + "# можно создать переменную, присвоив ей числовое значение\n", + "xx = 15\n", + "print(xx)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "a32d9952", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Я программирую на Питоне\n" + ] + } + ], + "source": [ + "# кроме того, переменной можно задать строковое (текстовое) значение\n", + "yy = \"Я программирую на Питоне\"\n", + "print(yy)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "69cb1b1b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Питон C++ PHP\n" + ] + } + ], + "source": [ + "# присваиваем разные значения сразу нескольким переменным\n", + "aa, bb, cc = \"Питон\", \"C++\", \"PHP\"\n", + "print(aa, bb, cc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7620d8a6", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "То же самое значение То же самое значение То же самое значение\n" + ] + } + ], + "source": [ + "# задаем одно и то же значение нескольким переменным\n", + "xxx = yyy = zzz = \"То же самое значение\"\n", + "print(xxx, yyy, zzz)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99cab062", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "помидоры огурцы картофель\n" + ] + } + ], + "source": [ + "my_list = [\"помидоры\", \"огурцы\", \"картофель\"]\n", + "aa1, bb1, cc1 = my_list\n", + "print(aa1, bb1, cc1)" + ] + }, + { + "cell_type": "markdown", + "id": "045a1f73", + "metadata": {}, + "source": [ + "### Автоматическое определение типа данных" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ba84959", + "metadata": {}, + "outputs": [], + "source": [ + "xx11 = 256 # в этом случае переменной x присваивается тип int (целочисленное значение)\n", + "yy11 = 0.25 # y становится float (десятичной дробью)\n", + "zz11 = \"Просто текст\" # z становится str (строкой)" + ] + }, + { + "cell_type": "markdown", + "id": "67217a7e", + "metadata": {}, + "source": [ + "### Как узнать тип переменной в Питоне" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3d2eb02", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \n" + ] + } + ], + "source": [ + "# узнаем тип переменных из предыдущего примера\n", + "print(type(xx11), type(yy11), type(zz11))" + ] + }, + { + "cell_type": "markdown", + "id": "ed77d032", + "metadata": {}, + "source": [ + "### Присвоение и преобразование типа данных" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc8004e4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \n" + ] + } + ], + "source": [ + "xx1 = str(25)\n", + "# число 25 превратится в строку\n", + "yy2 = int(25)\n", + "# число 25 останется целочисленным значением\n", + "zz3 = float(25)\n", + "# число 25 превратится в десятичную дробь\n", + "\n", + "print(type(xx1), type(yy2), type(zz3))" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "ae64da98", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "# Также тип данных можно изменить.\n", + "\n", + "# преобразуем строку, похожую на целое число, в целое число\n", + "print(type(int(\"25\")))" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "id": "59099e64", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "# или строку, похожую на дробь, в настоящую десятичную дробь\n", + "print(type(float(\"2.5\")))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a0d0f42", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "36\n", + "\n" + ] + } + ], + "source": [ + "# преобразуем дробь в целочисленное значение\n", + "# обратите внимание, что округления в большую\n", + "# сторону не происходит\n", + "print(int(36.6))\n", + "print(type(int(36.6)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e714ad7e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n" + ] + } + ], + "source": [ + "# конечно, и целое число, и дробь можно преобразовать в строку\n", + "print(type(str(25)))\n", + "print(type(str(36.6)))\n", + "\n", + "# Одним из наиболее очевидных применений является\n", + "# предварительная обработка #данных, поступивших,\n", + "# скажем, в формате строки (str), хотя с точки зрения\n", + "# логики это должно быть целое число (int)." + ] + }, + { + "cell_type": "markdown", + "id": "a6bb2d95", + "metadata": {}, + "source": [ + "### Именование переменных" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff9a943d", + "metadata": {}, + "outputs": [], + "source": [ + "# Посмотрим на допустимые названия переменных:\n", + "\n", + "# допустимые имена переменных\n", + "# variable = \"Просто переменная\"\n", + "# _variable = \"Просто переменная\"\n", + "# variable_ = \"Просто переменная\"\n", + "# my_variable = \"Просто переменная\"\n", + "# My_variable_123 = \"Просто переменная\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40a095e1", + "metadata": {}, + "outputs": [], + "source": [ + "# можно применить так называемый верблюжий регистр, camelCase\n", + "# все слова кроме первого начинаются с заглавной буквы и пишутся слитно\n", + "# camelCaseVariable = \"Верблюжий регистр\"\n", + "\n", + "# нотацию Паскаль, PascalCase (то же самое, только тепер все слова пишутся с заглавной)\n", + "# PascalCaseVariable = \"Нотация Паскаль\"\n", + "\n", + "# змеиный стиль, snake_case (с нижними подчеркиваниями)\n", + "# snake_case_variable = \"Змеиная нотация\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "960ff229", + "metadata": {}, + "outputs": [], + "source": [ + "# my-variable = 'Так делать нельзя'\n", + "# 123variable = 'Так делать нельзя'\n", + "# my variable = 'Так делать нельзя'\n", + "\n", + "# Также важно отметить, что служебные слова, например,\n", + "# print, int, str, list, dict, set не могут использоваться\n", + "# в качестве названий переменных. Другими словами,\n", + "# my_list или list_ можно использовать в качестве\n", + "# имени переменной, а вот просто list нельзя." + ] + }, + { + "cell_type": "markdown", + "id": "6437385a", + "metadata": {}, + "source": [ + "### Ответы на вопросы" + ] + }, + { + "cell_type": "markdown", + "id": "ed83ce22", + "metadata": {}, + "source": [ + "**Вопрос**. Как можно преобразовать список чисел таким образом, чтобы каждый элемент списка превратился в отдельную строку?" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "id": "f7159161", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3]\n", + "\n" + ] + } + ], + "source": [ + "list_ = [1, 2, 3]\n", + "print(str(list_))\n", + "print(type(str(list_)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59a85a5c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['1', '2', '3']" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вариант 1: объявить новый список и в цикле for помещать туда строковые значения\n", + "list_str = []\n", + "\n", + "for xeee in list_:\n", + " list_str.append(str(xeee))\n", + "\n", + "# list_str" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c218dd77", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['1', '2', '3']" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вариант 2: использовать list comprehension\n", + "# [str(xxx) for xxx in list_]" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "id": "9a05195c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['1', '2', '3']" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вариант 3: функции map() и list()\n", + "list(map(str, list_))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/makarov/chapter_1_var.py b/python/makarov/chapter_1_var.py new file mode 100644 index 00000000..7f34a5ea --- /dev/null +++ b/python/makarov/chapter_1_var.py @@ -0,0 +1,140 @@ +"""Глава 1. + +Переменные в Питоне. +""" + +# ### Как объявить переменную в Питоне + +# можно создать переменную, присвоив ей числовое значение +xx = 15 +print(xx) + +# кроме того, переменной можно задать строковое (текстовое) значение +yy = "Я программирую на Питоне" +print(yy) + +# присваиваем разные значения сразу нескольким переменным +aa, bb, cc = "Питон", "C++", "PHP" +print(aa, bb, cc) + +# задаем одно и то же значение нескольким переменным +xxx = yyy = zzz = "То же самое значение" +print(xxx, yyy, zzz) + +my_list = ["помидоры", "огурцы", "картофель"] +aa1, bb1, cc1 = my_list +print(aa1, bb1, cc1) + +# ### Автоматическое определение типа данных + +xx11 = 256 # в этом случае переменной x присваивается тип int +# (цлочисленное значение) +yy11 = 0.25 # y становится float (десятичной дробью) +zz11 = "Просто текст" # z становится str (строкой) + +# ### Как узнать тип переменной в Питоне + +# узнаем тип переменных из предыдущего примера +print(type(xx11), type(yy11), type(zz11)) + +# ### Присвоение и преобразование типа данных + +# + +xx1 = str(25) +# число 25 превратится в строку +yy2 = int(25) +# число 25 останется целочисленным значением +zz3 = float(25) +# число 25 превратится в десятичную дробь + +print(type(xx1), type(yy2), type(zz3)) + +# + +# Также тип данных можно изменить. + +# преобразуем строку, похожую на целое число, в целое число +print(type(int("25"))) +# - + +# или строку, похожую на дробь, в настоящую десятичную дробь +print(type(float("2.5"))) + +# преобразуем дробь в целочисленное значение +# обратите внимание, что округления в большую +# сторону не происходит +print(int(36.6)) +print(type(int(36.6))) + +# + +# конечно, и целое число, и дробь можно преобразовать в строку +print(type(str(25))) +print(type(str(36.6))) + +# Одним из наиболее очевидных применений является +# предварительная обработка #данных, поступивших, +# скажем, в формате строки (str), хотя с точки зрения +# логики это должно быть целое число (int). +# - + +# ### Именование переменных + +# + +# Посмотрим на допустимые названия переменных: + +# допустимые имена переменных +# variable = "Просто переменная" +# _variable = "Просто переменная" +# variable_ = "Просто переменная" +# my_variable = "Просто переменная" +# My_variable_123 = "Просто переменная" + +# + +# можно применить так называемый верблюжий регистр, camelCase +# все слова кроме первого начинаются с заглавной буквы и пишутся слитно +# camelCaseVariable = "Верблюжий регистр" + +# нотацию Паскаль, PascalCase (то же самое, только тепер все слова +# пишутся с заглавной) +# PascalCaseVariable = "Нотация Паскаль" + +# змеиный стиль, snake_case (с нижними подчеркиваниями) +# snake_case_variable = "Змеиная нотация" + +# + +# my-variable = 'Так делать нельзя' +# 123variable = 'Так делать нельзя' +# my variable = 'Так делать нельзя' + +# Также важно отметить, что служебные слова, например, +# print, int, str, list, dict, set не могут использоваться +# в качестве названий переменных. Другими словами, +# my_list или list_ можно использовать в качестве +# имени переменной, а вот просто list нельзя. +# - + +# ### Ответы на вопросы + +# **Вопрос**. Как можно преобразовать список чисел таким образом, +# чтобы каждый элемент списка превратился в отдельную строку? + +list_ = [1, 2, 3] +print(str(list_)) +print(type(str(list_))) + +# + +# вариант 1: объявить новый список и в цикле for помещать туда +# строковые значения +list_str = [] + +for xeee in list_: + list_str.append(str(xeee)) + +# list_str + +# + +# вариант 2: использовать list comprehension +# [str(xxx) for xxx in list_] +# - + +# вариант 3: функции map() и list() +list(map(str, list_)) diff --git a/python/makarov/chapter_2_dtype.ipynb b/python/makarov/chapter_2_dtype.ipynb new file mode 100644 index 00000000..9bdd20e8 --- /dev/null +++ b/python/makarov/chapter_2_dtype.ipynb @@ -0,0 +1,563 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 23, + "id": "0cd8e895", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Глава 2. Типы данных.'" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Глава 2. Типы данных.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "3fe65062", + "metadata": {}, + "source": [ + "## Какие типы данных есть в Питоне\n", + "\n", + "Некоторые типы данных позволяют записать только одну единицу информации в переменную. К ним, в частности, относятся\n", + "\n", + "- целочисленное значение (integer);\n", + "- десятичная дробь, или если быть более точным, число с плавающей запятой (float);\n", + "- комплексное число (complex);\n", + "- строка (string); и\n", + "- логическое значение (boolean).\n", + "\n", + "Также существуют типы данных, в которых могут содержаться несколько элементов. Сюда входят:\n", + "- списки (list);\n", + "- словари (dictionary);\n", + "- множества (set); и\n", + "- кортежи (tuple)." + ] + }, + { + "cell_type": "markdown", + "id": "ab696dc3", + "metadata": {}, + "source": [ + "## Работа с числами" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "6c47e0d3", + "metadata": {}, + "outputs": [], + "source": [ + "aa = 25 # целое число (int)\n", + "bb = 2.5 # число с плавающей точкой (float)\n", + "cc = 3 + 25j # комплексное число (complex)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "2af52ebd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2000.0\n", + "\n" + ] + } + ], + "source": [ + "# float in exp\n", + "dd = 2e3 # 2 умножить на 10 в степени 3\n", + "print(dd)\n", + "print(type(dd))" + ] + }, + { + "cell_type": "markdown", + "id": "5c884c67", + "metadata": {}, + "source": [ + "## Операции с числами" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "f0ff08e1", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4 2 4 2.0 8\n", + "3\n", + "1\n" + ] + } + ], + "source": [ + "# сложение, вычитание, умножение, деление, возведение в степень\n", + "print(2 + 2, 4 - 2, 2 * 2, 4 / 2, 2**3)\n", + "\n", + "# разделим 7 на 2, и найдем целую часть и остаток\n", + "\n", + "# целая часть\n", + "print(7 // 2)\n", + "\n", + "# остаток от деления\n", + "print(7 % 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "48205c38", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True False True False\n", + "False\n", + "True\n" + ] + } + ], + "source": [ + "# Также напомню про операторы сравнения.\n", + "\n", + "# больше, меньше, больше или равно и меньше или равно\n", + "# print(4 > 2, 4 < 2, 4 >= 2, 4 <= 2)\n", + "\n", + "# равенство\n", + "# print(2 == 4)\n", + "\n", + "# и новый для нас оператор неравенства\n", + "# print(2 != 4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc23c21c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "# Кроме этого, существуют и чисто логические операции И, ИЛИ и НЕ.\n", + "\n", + "# логическое И, обе операции должны быть истинны\n", + "# print(4 > 2 and 2 != 3)\n", + "\n", + "# логическое ИЛИ, хотя бы одна из операций должна быть истинна\n", + "# print(4 < 2 or 2 == 2)\n", + "\n", + "# логическое НЕ, перевод истинного значения в ложное и наоборот\n", + "# print(not (4 == 4))" + ] + }, + { + "cell_type": "markdown", + "id": "876c7522", + "metadata": {}, + "source": [ + "## Перевод чисел в другую систему счисления" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "23e120e4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0b11001\n", + "25\n" + ] + } + ], + "source": [ + "# создадим число в десятичной системе\n", + "d11 = 25\n", + "\n", + "# переведем в двоичную (binary)\n", + "bin_d = bin(d11)\n", + "print(bin_d)\n", + "\n", + "# переведем обратно в десятичную\n", + "print(int(bin_d, 2))\n", + "\n", + "# oct() и hex()" + ] + }, + { + "cell_type": "markdown", + "id": "eabce126", + "metadata": {}, + "source": [ + "## Строковые данные" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "0f955ce5", + "metadata": {}, + "outputs": [], + "source": [ + "string_1 = \"это строка\"\n", + "string_2 = \"это тоже строка\"\n", + "\n", + "\n", + "multi_string = \"\"\"Мы все учились понемногу\n", + "Чему-нибудь и как-нибудь,\n", + "Так воспитаньем, слава богу,\n", + "У нас немудрено блеснуть.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "c4702852", + "metadata": {}, + "source": [ + "## Длина строки" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "e2ab55f8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "105" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(multi_string)" + ] + }, + { + "cell_type": "markdown", + "id": "adfb8f5a", + "metadata": {}, + "source": [ + "## Объединение строк" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca4dc761", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Программирование на Питоне'" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим три строки\n", + "a123, b123, c123 = \"Программирование\", \"на\", \"Питоне\"\n", + "\n", + "# соединим с помощью + и добавим пробелы ' '\n", + "# a123 + \" \" + b123 + \" \" + c123" + ] + }, + { + "cell_type": "markdown", + "id": "20e74ac1", + "metadata": {}, + "source": [ + "## Индекс символа в строке\n", + "\n", + "Питон автоматически создает два индекса, нумерует символы от начала и\n", + "до конца (начиная с нуля, положительный индекс) и с конца и до начала\n", + "(начиная с −1, отрицательный индекс)." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "2fc02da4", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "М\n", + ".\n" + ] + } + ], + "source": [ + "# выведем первый элемент строки multi_string\n", + "print(multi_string[0])\n", + "\n", + "# теперь выведем последний элемент\n", + "print(multi_string[-1])" + ] + }, + { + "cell_type": "markdown", + "id": "3fac558f", + "metadata": {}, + "source": [ + "## Срезы строк" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "61aef9b7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "все\n", + "\n", + "Мы\n", + "все учились понемногу\n", + "Чему-нибудь и как-нибудь,\n", + "Так воспитаньем, слава богу,\n", + "У нас немудрено блеснуть.\n" + ] + } + ], + "source": [ + "# выберем элементы с четвертого по шестой\n", + "print(multi_string[3:6])\n", + "print()\n", + "# выведем все элементы вплоть до второго\n", + "print(multi_string[:2])\n", + "\n", + "# а также все элементы, начиная с четвертого\n", + "print(multi_string[3:])" + ] + }, + { + "cell_type": "markdown", + "id": "b61a3bba", + "metadata": {}, + "source": [ + "## Циклы в строках" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "f34a0204", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "П\n", + "и\n", + "т\n", + "о\n", + "н\n" + ] + } + ], + "source": [ + "# выведем буквы в слове Питон\n", + "for i in \"Питон\":\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "id": "8688f649", + "metadata": {}, + "source": [ + "## Методы .strip() и .split()\n", + "Метод .strip() удаляет символы в начале и в конце строки.\n", + "Это бывает полезно, если в базе данных значения записаны,\n", + "например, вместе со служебными символами и от них нужно избавиться.\n", + "\n", + "Метод .split() делит строку на части. По умолчанию, по пробелам,\n", + "но можно указать и другой разделитель." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "fb1fbf1e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "15 849 302\n", + "15 849 302\n", + "['Мы', 'все', 'учились', 'понемногу', 'Чему-нибудь', 'и', 'как-нибудь,', 'Так', 'воспитаньем,', 'слава', 'богу,', 'У', 'нас', 'немудрено', 'блеснуть.']\n" + ] + }, + { + "data": { + "text/plain": [ + "15" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# применим метод .strip(), чтобы удалить *\n", + "print(\"***15 849 302*****\".strip(\"*\"))\n", + "\n", + "# если ничего не указать в качестве аргумента, то удаляются пробелы по краям строки\n", + "print(\" 15 849 302 \".strip())\n", + "\n", + "# применим метод .split(), чтобы разделить строку на части\n", + "print(multi_string.split())\n", + "\n", + "# функция len() применима и к спискам\n", + "len(multi_string.split())" + ] + }, + { + "cell_type": "markdown", + "id": "4edbf35f", + "metadata": {}, + "source": [ + "## Замена символа в строке" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24237ca2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20.25\n", + "\n" + ] + } + ], + "source": [ + "# предположим данные содержатся вот в таком формате\n", + "dataaa = \"20,25\"\n", + "\n", + "# теперь заменим ',' на '.'\n", + "dataaa = dataaa.replace(\",\", \".\")\n", + "\n", + "# и преобразуем в число\n", + "# dataaa = float(dataaa)\n", + "# print(dataaa)\n", + "# print(type(dataaa))" + ] + }, + { + "cell_type": "markdown", + "id": "a318d8ad", + "metadata": {}, + "source": [ + "## Логические значения" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8359febe", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Значение переменной истинно\n" + ] + } + ], + "source": [ + "# создадим переменную и запишем в нее логическое значение True\n", + "# (обязательно с большой буквы)\n", + "var1234 = True\n", + "type(var1234)\n", + "\n", + "\n", + "# напишем небольшую программу, которая будет показывать,\n", + "# какое значение содержится в переменной var\n", + "\n", + "# if var1234 == True:\n", + "# print(\"Значение переменной истинно\")\n", + "# else:\n", + "# print(\"Значение переменной ложно\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/makarov/chapter_2_dtype.py b/python/makarov/chapter_2_dtype.py new file mode 100644 index 00000000..b174940f --- /dev/null +++ b/python/makarov/chapter_2_dtype.py @@ -0,0 +1,204 @@ +"""Глава 2. + +Типы данных. +""" + +# ## Какие типы данных есть в Питоне +# +# Некоторые типы данных позволяют записать только одну единицу +# информации в переменную. К ним, в частности, относятся +# +# - целочисленное значение (integer); +# - десятичная дробь, или если быть более точным, число с плавающей +# запятой (float); +# - комплексное число (complex); +# - строка (string); и +# - логическое значение (boolean). +# +# Также существуют типы данных, в которых могут содержаться +# несколько элементов. Сюда входят: +# - списки (list); +# - словари (dictionary); +# - множества (set); и +# - кортежи (tuple). + +# ## Работа с числами + +aa = 25 # целое число (int) +bb = 2.5 # число с плавающей точкой (float) +cc = 3 + 25j # комплексное число (complex) + +# float in exp +dd = 2e3 # 2 умножить на 10 в степени 3 +print(dd) +print(type(dd)) + +# ## Операции с числами + +# + +# сложение, вычитание, умножение, деление, возведение в степень +print(2 + 2, 4 - 2, 2 * 2, 4 / 2, 2**3) + +# разделим 7 на 2, и найдем целую часть и остаток + +# целая часть +print(7 // 2) + +# остаток от деления +print(7 % 2) + +# + +# Также напомню про операторы сравнения. + +# больше, меньше, больше или равно и меньше или равно +# print(4 > 2, 4 < 2, 4 >= 2, 4 <= 2) + +# равенство +# print(2 == 4) + +# и новый для нас оператор неравенства +# print(2 != 4) + +# + +# Кроме этого, существуют и чисто логические операции И, ИЛИ и НЕ. + +# логическое И, обе операции должны быть истинны +# print(4 > 2 and 2 != 3) + +# логическое ИЛИ, хотя бы одна из операций должна быть истинна +# print(4 < 2 or 2 == 2) + +# логическое НЕ, перевод истинного значения в ложное и наоборот +# print(not (4 == 4)) +# - + +# ## Перевод чисел в другую систему счисления + +# + +# создадим число в десятичной системе +d11 = 25 + +# переведем в двоичную (binary) +bin_d = bin(d11) +print(bin_d) + +# переведем обратно в десятичную +print(int(bin_d, 2)) + +# oct() и hex() +# - + +# ## Строковые данные + +# + +string_1 = "это строка" +string_2 = "это тоже строка" + + +multi_string = """Мы все учились понемногу +Чему-нибудь и как-нибудь, +Так воспитаньем, слава богу, +У нас немудрено блеснуть.""" +# - + +# ## Длина строки + +len(multi_string) + +# ## Объединение строк + +# + +# создадим три строки +a123, b123, c123 = "Программирование", "на", "Питоне" + +# соединим с помощью + и добавим пробелы ' ' +# a123 + " " + b123 + " " + c123 +# - + +# ## Индекс символа в строке +# +# Питон автоматически создает два индекса, нумерует символы от начала и +# до конца (начиная с нуля, положительный индекс) и с конца и до начала +# (начиная с −1, отрицательный индекс). + +# + +# выведем первый элемент строки multi_string +print(multi_string[0]) + +# теперь выведем последний элемент +print(multi_string[-1]) +# - + +# ## Срезы строк + +# + +# выберем элементы с четвертого по шестой +print(multi_string[3:6]) +print() +# выведем все элементы вплоть до второго +print(multi_string[:2]) + +# а также все элементы, начиная с четвертого +print(multi_string[3:]) +# - + +# ## Циклы в строках + +# выведем буквы в слове Питон +for i in "Питон": + print(i) + +# ## Методы .strip() и .split() +# Метод .strip() удаляет символы в начале и в конце строки. +# Это бывает полезно, если в базе данных значения записаны, +# например, вместе со служебными символами и от них нужно избавиться. +# +# Метод .split() делит строку на части. По умолчанию, по пробелам, +# но можно указать и другой разделитель. + +# + +# применим метод .strip(), чтобы удалить * +print("***15 849 302*****".strip("*")) + +# если ничего не указать в качестве аргумента, то удаляются пробелы +# по краям строки +print(" 15 849 302 ".strip()) + +# применим метод .split(), чтобы разделить строку на части +print(multi_string.split()) + +# функция len() применима и к спискам +len(multi_string.split()) +# - + +# ## Замена символа в строке + +# + +# предположим данные содержатся вот в таком формате +dataaa = "20,25" + +# теперь заменим ',' на '.' +dataaa = dataaa.replace(",", ".") + +# и преобразуем в число +# dataaa = float(dataaa) +# print(dataaa) +# print(type(dataaa)) +# - + +# ## Логические значения + +# + +# создадим переменную и запишем в нее логическое значение True +# (обязательно с большой буквы) +var1234 = True +type(var1234) + + +# напишем небольшую программу, которая будет показывать, +# какое значение содержится в переменной var +# +# if var1234 == True: +# print("Значение переменной истинно") +# else: +# print("Значение переменной ложно") diff --git a/python/makarov/chapter_3_loop.ipynb b/python/makarov/chapter_3_loop.ipynb new file mode 100644 index 00000000..5c626623 --- /dev/null +++ b/python/makarov/chapter_3_loop.ipynb @@ -0,0 +1,1085 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 12, + "id": "95ef0ce5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Глава 3. Условия и циклы. Продолжение.'" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Глава 3. Условия и циклы. Продолжение.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "fe58791e", + "metadata": {}, + "source": [ + "## Еще раз про условия с if\n", + "\n", + "Помимо базовой уже известной нам структуры if-else, мы также\n", + "можем прописать несколько условий (multi-way decisions) с помощью\n", + "if-elif-else. Слово elif в данном случае как раз и позволяет\n", + "добавить новые условия." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "7182b456", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Medium\n" + ] + } + ], + "source": [ + "# импортируем библиотеку numpy\n", + "import numpy as np\n", + "\n", + "xxx = 42 # зададим число\n", + "\n", + "# и пропишем условия (не забывайте про двоеточие и отступ)\n", + "if xxx < 10:\n", + " print(\"Small\")\n", + "elif xxx < 100:\n", + " print(\"Medium\")\n", + "else:\n", + " print(\"Large\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d505085", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Medium\n" + ] + } + ], + "source": [ + "# запросим число у пользователя\n", + "\n", + "# преобразуем в тип int\n", + "number = 42 # int(number)\n", + "\n", + "# и наконец классифицируем\n", + "if number < 10:\n", + " print(\"Small\")\n", + "elif number < 100:\n", + " print(\"Medium\")\n", + "else:\n", + " print(\"Large\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "6cdf74db", + "metadata": {}, + "outputs": [], + "source": [ + "# Помимо этого одно условие может быть вложено в\n", + "# другое (nested decisions). Приведем пример.\n", + "\n", + "# # запрашиваем число\n", + "# y = input('Введите число: ')\n", + "#\n", + "# # проверяем первое условие (не пустая ли строка), если оно выполняется\n", + "# if len(y) != 0:\n", + "#\n", + "# # преобразуем в тип int\n", + "# y = int(y)\n", + "#\n", + "# # и классифицируем\n", + "# if y < 10:\n", + "# print('Small')\n", + "# elif y < 100:\n", + "# print('Medium')\n", + "# else:\n", + "# print('Large')\n", + "#\n", + "# # в противном, говорим, что ввод пустой\n", + "# else:\n", + "# print('Ввод пустой')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23e32f63", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Medium\n" + ] + } + ], + "source": [ + "# В коде можно прописать сразу несколько условий в одном\n", + "# выражении. Например, можно объединить if c логическими\n", + "# операторами and или or.\n", + "\n", + "zzzz = 42\n", + "\n", + "# если zzzz больше 10 и одновременно меньше 100\n", + "if 10 < zzzz < 100:\n", + "\n", + " # у нас среднее число\n", + " print(\"Medium\")\n", + "\n", + "# в противном случае оно либо маленькое либо большое\n", + "else:\n", + " print(\"Small or Large\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "ef0c7d10", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Small or Large\n" + ] + } + ], + "source": [ + "# А также логическим ИЛИ.\n", + "zz12 = 2\n", + "\n", + "# если z меньше 10 или больше 100\n", + "if zz12 < 10 or zz12 > 100:\n", + "\n", + " # оно либо маленькое либо большое\n", + " print(\"Small or Large\")\n", + "\n", + "# в противном случае оно среднее\n", + "else:\n", + " print(\"Medium\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "f460c960", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Слово найдено\n", + "Такого числа в списке нет\n" + ] + } + ], + "source": [ + "# оператор in возвращает True, если элемент входит в объект;\n", + "# оператор not in возвращает True, если элемент не входит в объект.\n", + "# Посмотрим на примерах.\n", + "\n", + "# можно проверить вхождение слова в строку\n", + "sentence = \"To be, or not to be, that is the question\"\n", + "word = \"question\"\n", + "\n", + "if word in sentence:\n", + " print(\"Слово найдено\")\n", + "\n", + "# или отсутствие элемента в списке\n", + "number_list = [2, 3, 4, 6, 7]\n", + "number = 5\n", + "\n", + "if number not in number_list:\n", + " print(\"Такого числа в списке нет\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71d94aff", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Нашлись\n", + "Есть\n" + ] + } + ], + "source": [ + "# Применим оператор in к словарю.\n", + "\n", + "# возьмем очень простой словарь\n", + "dig = {\"apple\": 3, \"tomato\": 6, \"carrot\": 2}\n", + "# вначале поищем яблоки среди ключей словаря\n", + "if \"apple\" in dig:\n", + " print(\"Нашлись\")\n", + "\n", + "# а затем посмотрим, нет ли числа 6 среди его значений\n", + "# с помощью метода .values()\n", + "\n", + "if 6 in dig.values():\n", + " print(\"Есть\")" + ] + }, + { + "cell_type": "markdown", + "id": "17917287", + "metadata": {}, + "source": [ + "# Циклы" + ] + }, + { + "cell_type": "markdown", + "id": "b1214d7e", + "metadata": {}, + "source": [ + "## Цикл for" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "ebbdfadd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "# поочередно выведем элементы списка\n", + "number_list = [1, 2, 3]\n", + "\n", + "# не забывая про двоеточие и отступ\n", + "for number in number_list:\n", + " print(number)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "355fc252", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "apple [3, 'kg']\n", + "tomato [6, 'pcs']\n", + "carrot [2, 'kg']\n" + ] + } + ], + "source": [ + "# Мы также умеем выводить элементы словаря.\n", + "\n", + "# создадим словарь, значениями которого будут списки из двух элементов\n", + "dddd = {\"apple\": [3, \"kg\"], \"tomato\": [6, \"pcs\"], \"carrot\": [2, \"kg\"]}\n", + "\n", + "# затем создадим две переменные-контейнера и применим метод .items()\n", + "for kk, vv in dddd.items():\n", + " print(kk, vv)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a50cd35", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n", + "6\n", + "2\n" + ] + } + ], + "source": [ + "# Помимо этого мы можем вывести только ключи или только\n", + "# значения с помощью методов .keys() и .values() соответственно.\n", + "\n", + "# Предположим, что мы хотим вывести только числа\n", + "# (первый элемент значения словаря).\n", + "\n", + "# возьмем только одну переменную и применим метод .values()\n", + "for vvv in dddd.values():\n", + " # значение представляет собой список, выведем его первый элемент с индексом [0]\n", + " print(vvv[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "69e1deca", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n" + ] + } + ], + "source": [ + "# Цикл for можно применить к массиву Numpy.\n", + "\n", + "\n", + "# создадим массив и поместим в переменную number_array\n", + "number_array = np.array([1, 2, 3])\n", + "\n", + "# пройдемся по нему с помощью цикла for\n", + "for number in number_array:\n", + " print(number)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0e5af6f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "client ID: 1\n", + "name: Анна\n", + "age: 24\n", + "sex: male\n", + "revenue: 12000\n", + "\n", + "client ID: 2\n", + "name: Илья\n", + "age: 18\n", + "sex: female\n", + "revenue: 8000\n", + "\n" + ] + } + ], + "source": [ + "# Помимо этого мы можем вложить один цикл for в другой.\n", + "# Предположим, что у нас есть следующая база данных клиентов.\n", + "\n", + "clientss = {\n", + " 1: {\"name\": \"Анна\", \"age\": 24, \"sex\": \"male\", \"revenue\": 12000},\n", + " 2: {\"name\": \"Илья\", \"age\": 18, \"sex\": \"female\", \"revenue\": 8000},\n", + "}\n", + "\n", + "# в первом цикле for поместим id и информацию о клиентах в переменные id и info\n", + "for idd, infoo in clientss.items():\n", + "\n", + " # выведем id клиента\n", + " print(\"client ID: \" + str(idd))\n", + "\n", + " # во втором цикле возьмем информацию об очередном клиенте (тоже словарь)\n", + " for k12, v12 in infoo.items():\n", + "\n", + " # и выведем каждый ключ (название поля) и значение (саму информацию)\n", + " print(k12 + \": \" + str(v12))\n", + "\n", + " # добавим пустую строку после того, как выведем информацию об одном клиенте\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "id": "727e10c2", + "metadata": {}, + "source": [ + "### Функции range() и enumerate()\n", + "### Функция range()" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "fc923d2d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n", + "3\n", + "4\n" + ] + } + ], + "source": [ + "# создадим последовательность от 0 до 4\n", + "for i in range(5):\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "73e36074", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "2\n", + "3\n", + "4\n", + "5\n" + ] + } + ], + "source": [ + "# от 1 до 5\n", + "for i in range(1, 6):\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "3fb2f62f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "2\n", + "4\n" + ] + } + ], + "source": [ + "# и от 0 до 5 с шагом 2 (то есть будем выводить числа через одно)\n", + "for i in range(0, 6, 2):\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "id": "c18075af", + "metadata": {}, + "source": [ + "Функция range() принимает от одного до трех параметров,\n", + "\n", + "- если передать только один параметр, то мы начнем последовательность с нул\n", + " и закончим на элементе, предшествующем нашему параметру. В примере выше мы\n", + " передали параметр «пять» (range(5)) и получили последовательность 0, 1, 2, 3, 4;\n", + "- если указать два параметра, то мы начнем последовательность с первого параметра\n", + "и законим на элементе, предшествующем второму параметру. В частности, если написать\n", + "range(1, 6), то получится 1, 2, 3, 4, 5;\n", + "- третий параметр устанавливает шаг. По умолчанию он равен единице, однако если,\n", + "например, написать, range(0, 6, 2), то мы получим 0, 2, 4.\n", + "\n", + "Что интересно, если совместить range() с функцией len(), то такую конструкцию можно использовать для того, чтобы в одном цикле вывести все элементы, например, двух списков по их индексу." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aae761c5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Январь 47\n", + "Февраль 75\n", + "Март 79\n", + "Апрель 94\n", + "Май 123\n", + "Июнь 209\n", + "Июль 233\n", + "Август 214\n", + "Сентябрь 197\n", + "Октябрь 130\n", + "Ноябрь 87\n", + "Декабрь 55\n" + ] + } + ], + "source": [ + "# возьмем месяцы года\n", + "months = [\n", + " \"Январь\",\n", + " \"Февраль\",\n", + " \"Март\",\n", + " \"Апрель\",\n", + " \"Май\",\n", + " \"Июнь\",\n", + " \"Июль\",\n", + " \"Август\",\n", + " \"Сентябрь\",\n", + " \"Октябрь\",\n", + " \"Ноябрь\",\n", + " \"Декабрь\",\n", + "]\n", + "\n", + "# и продажи мороженого в тыс. рублей в каждый из месяцев\n", + "sales = [47, 75, 79, 94, 123, 209, 233, 214, 197, 130, 87, 55]\n", + "\n", + "# задав последовательность через range(len()),\n", + "# for i in range(len(months)):\n", + "\n", + "# мы можем вывести каждый из элементов обоих списков в одном цикле\n", + "# print(months[i], sales[i])" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "e9ae318a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "3\n", + "2\n", + "1\n", + "0\n" + ] + } + ], + "source": [ + "# Интересно, что по последовательности, создаваемой\n", + "# функцией range() можно пройтись и в обратном порядке\n", + "# от конца к началу. Сделать это можно тремя способами.\n", + "#\n", + "# Способ 1. Использовать функцию reversed(). Эта функция\n", + "# меняет порядок элементов списка на обратный.\n", + "\n", + "# создадим список\n", + "my_list = [0, 1, 2, 3, 4]\n", + "\n", + "# передадим его функции reversed() и\n", + "# выведем каждый из элементов списка с помощью цикла for\n", + "for i in reversed(my_list):\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "50acba8c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "3\n", + "2\n", + "1\n", + "0\n" + ] + } + ], + "source": [ + "# Одновременно ей можно передать последовательность, создаваемую range() и вывести результат в цикле for.\n", + "\n", + "for i in reversed(range(5)):\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3f9dc86", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "3\n", + "2\n", + "1\n", + "\n", + "4\n", + "3\n", + "2\n", + "1\n", + "0\n" + ] + } + ], + "source": [ + "# Способ 2. Указать\n", + "# в качестве параметра шага. При этом важно, чтобы\n", + "# первым параметром указывался конечный элемент списка,\n", + "# а вторым — начальный.\n", + "\n", + "for i in range(4, 0, -1):\n", + " print(i)\n", + "\n", + "print()\n", + "# Обратите внимание, что в примере выше 4 входит в\n", + "# создаваемую последовательность, а вот 0 уже нет.\n", + "# Для того чтобы вывести 0, вторым параметром нужно\n", + "# также указать\n", + "\n", + "for i in range(4, -1, -1):\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f131b4f9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "4\n", + "3\n", + "2\n", + "1\n", + "0\n" + ] + } + ], + "source": [ + "# Способ 3. Функция sorted(). Наконец, хотя в\n", + "# случае это явно не оптимальный вариант, можно\n", + "# использовать функцию sorted(), которая\n", + "# сортирует элементы списка по убыванию, если\n", + "# передать ей параметр reverse = True.\n", + "\n", + "# создадим последовательность от 0 до 4\n", + "rrr = range(5)\n", + "\n", + "# отсортируем ее по убыванию\n", + "sorted_values = sorted(rrr, reverse=True)\n", + "\n", + "# выведем элементы отсортированной последовательности\n", + "for i in sorted_values:\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "id": "cd941656", + "metadata": {}, + "source": [ + "### Функция enumerate()\n", + "\n", + "Мы можем использовать эту функцию, если у нас есть, например, список и,проходясь\n", + "в цикле по этому списку, мы хотим также получить порядковый номер (индекс) элементов списка." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "1007c351", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 Понедельник\n", + "1 Вторник\n", + "2 Среда\n", + "3 Четверг\n", + "4 Пятница\n", + "5 Суббота\n", + "6 Воскресенье\n" + ] + } + ], + "source": [ + "# пусть дан список с днями недели\n", + "days = [\n", + " \"Понедельник\",\n", + " \"Вторник\",\n", + " \"Среда\",\n", + " \"Четверг\",\n", + " \"Пятница\",\n", + " \"Суббота\",\n", + " \"Воскресенье\",\n", + "]\n", + "\n", + "# выведем индекс (i) и сами элементы списка (day)\n", + "for i, day in enumerate(days):\n", + " print(i, day)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "f351e1a9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 Понедельник\n", + "2 Вторник\n", + "3 Среда\n", + "4 Четверг\n", + "5 Пятница\n", + "6 Суббота\n", + "7 Воскресенье\n" + ] + } + ], + "source": [ + "# так же выведем индекс и элементы списка, но начнем с 1\n", + "for i, day in enumerate(days, 1):\n", + " print(i, day)" + ] + }, + { + "cell_type": "markdown", + "id": "f96305f8", + "metadata": {}, + "source": [ + "## Цикл while\n", + "\n", + "Цикл выполняется пока верно прописанное в нем условие." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "055da12d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Текущее значение счетчика: 0\n", + "Новое значение счетчика: 1\n", + "\n", + "Текущее значение счетчика: 1\n", + "Новое значение счетчика: 2\n", + "\n", + "Текущее значение счетчика: 2\n", + "Новое значение счетчика: 3\n", + "\n" + ] + } + ], + "source": [ + "# зададим начальное значение счетчика\n", + "iii = 0\n", + "\n", + "# пока счетчик меньше трех\n", + "while iii < 3:\n", + "\n", + " # в каждом цикле будем выводить его текущее значение\n", + " print(\"Текущее значение счетчика: \" + str(iii))\n", + "\n", + " # внутри цикла не забудем \"нарастить\" счетчик\n", + " iii = iii + 1\n", + "\n", + " # и выведем новое значение\n", + " print(\"Новое значение счетчика: \" + str(iii))\n", + "\n", + " # добавим пустую строку\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c6259fe", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n", + "1\n", + "2\n" + ] + } + ], + "source": [ + "# Небольшой лайфхак. Вместо того, чтобы\n", + "# писать i = i + 1 Питон позволяет\n", + "# использовать короткую запись\n", + "# (shorthand operator): i += 1.\n", + "\n", + "i123 = 0\n", + "\n", + "while i123 < 3:\n", + " print(i123)\n", + " i123 += 1" + ] + }, + { + "cell_type": "markdown", + "id": "7777fb6f", + "metadata": {}, + "source": [ + "### Операторы break и continue\n", + "#### Оператор break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce96ee9d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 {'name': 'Анна', 'age': 24, 'sex': 'male', 'revenue': 12000}\n" + ] + } + ], + "source": [ + "# вновь возьмем словарь clients\n", + "clients1 = {\n", + " 1: {\"name\": \"Анна\", \"age\": 24, \"sex\": \"male\", \"revenue\": 12000},\n", + " 2: {\"name\": \"Илья\", \"age\": 18, \"sex\": \"female\", \"revenue\": 8000},\n", + "}\n", + "\n", + "# в цикле пройдемся по ключам и значениям словаря\n", + "for iddd, info1 in clients1.items():\n", + "\n", + " # и выведем их\n", + " print(iddd, info1)\n", + "\n", + " # однако уже после первого исполнения цикла, прервем его\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "36079de5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n", + "5\n", + "4\n" + ] + } + ], + "source": [ + "# зададим начальное значение счетчика\n", + "xxx = 6\n", + "\n", + "# будем исполнять цикл пока x не равен нулю\n", + "while xxx != 0:\n", + "\n", + " # выведем текущее значение счетчика\n", + " print(xxx)\n", + "\n", + " # и уменьшим (!) его на 1\n", + " xxx -= 1\n", + "\n", + " # если значение счетчика станет равным 3, прервем цикл\n", + " if xxx == 3:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "id": "457294f2", + "metadata": {}, + "source": [ + "#### Оператор continue" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41001131", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2\n", + "4\n", + "6\n", + "8\n", + "10\n" + ] + } + ], + "source": [ + "# с помощью функции range создадим последовательность от 1 до 10\n", + "for i in range(1, 11):\n", + "\n", + " # если остаток от деления на два не равен нулю (то есть число нечетное)\n", + " if i % 2 != 0:\n", + "\n", + " # идем к следующему числу последовательности\n", + " continue\n", + "\n", + " # в противном случае выводим число\n", + " # else:\n", + " print(i)" + ] + }, + { + "cell_type": "markdown", + "id": "3c2e9c57", + "metadata": {}, + "source": [ + "### Форматирование строк в функции print()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5efe7e9", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Понедельник - день тяжелый\n", + "Понедельник - день тяжелый\n" + ] + } + ], + "source": [ + "# снова возьмем список с днями недели\n", + "days = [\n", + " \"Понедельник\",\n", + " \"Вторник\",\n", + " \"Среда\",\n", + " \"Четверг\",\n", + " \"Пятница\",\n", + " \"Суббота\",\n", + " \"Воскресенье\",\n", + "]\n", + "\n", + "# и для простоты поместим слово \"Понедельник\" в переменную Monday\n", + "Monday = days[0]\n", + "# Monday\n", + "\n", + "print(f\"{Monday} - день тяжелый\")\n", + "\n", + "# То же самое можно сделать с помощью метода .format().\n", + "\n", + "# print(\"{} - день тяжелый\".format(Monday))" + ] + }, + { + "cell_type": "markdown", + "id": "5efef9f9", + "metadata": {}, + "source": [ + "## Обобщим сказанное\n", + "Систематизируем пройденное на сегодняшнем занятии. В первой части мы вновь\n", + "обратились к условиям с if и научились\n", + "\n", + "- создавать множественные условия с if-elif-else;\n", + "- вкладывать одно условие в другое;\n", + "- объединять несколько условий с помощью логических операторов and и or; а также\n", + "- использовать конструкции if + in и if + not in, чтобы проверить вхождение\n", + "элемента в список или, например, словарь.\n", + "\n", + "Во второй части мы продолжили изучать цикл for и познакомились с циклом while.\n", + "Мы узнали, что\n", + "- циклы, как и условия, можно вкладывать один в другой;\n", + "- с помощью функции range() мы можем создавать новую последовательность элементов;\n", + "- функция enumerate() создает индекс для существующей последовательности;\n", + "- цикл while выполняется пока верно определенное условие, а чтобы он не стал\n", + "бесконечным, нужно использовать счетчик.\n", + "\n", + "Кроме того, мы узнали, что циклами можно управлять,\n", + "- оператор break позволяет прервать выполнение цикла;\n", + "- оператор continue прерывает выполнение конкретной итерации, но сам цикл продолжает исполняться.\n", + "В заключительной части занятия мы узнали, как можно форматировать строковые\n", + "значения и переменные через f-строки и метод .format()." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/makarov/chapter_3_loop.py b/python/makarov/chapter_3_loop.py new file mode 100644 index 00000000..784e502a --- /dev/null +++ b/python/makarov/chapter_3_loop.py @@ -0,0 +1,489 @@ +"""Глава 3. + +Условия и циклы. Продолжение. +""" + +# ## Еще раз про условия с if +# +# Помимо базовой уже известной нам структуры if-else, мы также +# можем прописать несколько условий (multi-way decisions) с помощью +# if-elif-else. Слово elif в данном случае как раз и позволяет +# добавить новые условия. + +# + +# импортируем библиотеку numpy +# import numpy as np + +xxx = 42 # зададим число + +# и пропишем условия (не забывайте про двоеточие и отступ) +if xxx < 10: + print("Small") +elif xxx < 100: + print("Medium") +else: + print("Large") + +# + +# запросим число у пользователя + +# преобразуем в тип int +number = 42 # int(number) + +# и наконец классифицируем +if number < 10: + print("Small") +elif number < 100: + print("Medium") +else: + print("Large") + +# + +# Помимо этого одно условие может быть вложено в +# другое (nested decisions). Приведем пример. + +# # запрашиваем число +# y = input('Введите число: ') +# +# # проверяем первое условие (не пустая ли строка), если оно выполняется +# if len(y) != 0: +# +# # преобразуем в тип int +# y = int(y) +# +# # и классифицируем +# if y < 10: +# print('Small') +# elif y < 100: +# print('Medium') +# else: +# print('Large') +# +# # в противном, говорим, что ввод пустой +# else: +# print('Ввод пустой') + +# + +# В коде можно прописать сразу несколько условий в одном +# выражении. Например, можно объединить if c логическими +# операторами and или or. + +zzzz = 42 + +# если zzzz больше 10 и одновременно меньше 100 +if 10 < zzzz < 100: + + # у нас среднее число + print("Medium") + +# в противном случае оно либо маленькое либо большое +else: + print("Small or Large") + +# + +# А также логическим ИЛИ. +zz12 = 2 + +# если z меньше 10 или больше 100 +if zz12 < 10 or zz12 > 100: + + # оно либо маленькое либо большое + print("Small or Large") + +# в противном случае оно среднее +else: + print("Medium") + +# + +# оператор in возвращает True, если элемент входит в объект; +# оператор not in возвращает True, если элемент не входит в объект. +# Посмотрим на примерах. + +# можно проверить вхождение слова в строку +sentence = "To be, or not to be, that is the question" +word = "question" + +if word in sentence: + print("Слово найдено") + +# или отсутствие элемента в списке +number_list = [2, 3, 4, 6, 7] +number = 5 + +if number not in number_list: + print("Такого числа в списке нет") + +# + +# Применим оператор in к словарю. + +# возьмем очень простой словарь +dig = {"apple": 3, "tomato": 6, "carrot": 2} +# вначале поищем яблоки среди ключей словаря +if "apple" in dig: + print("Нашлись") + +# а затем посмотрим, нет ли числа 6 среди его значений +# с помощью метода .values() + +if 6 in dig.values(): + print("Есть") +# - + +# # Циклы + +# ## Цикл for + +# + +# поочередно выведем элементы списка +number_list = [1, 2, 3] + +# не забывая про двоеточие и отступ +for number in number_list: + print(number) + +# + +# Мы также умеем выводить элементы словаря. + +# создадим словарь, значениями которого будут списки из двух элементов +dddd = {"apple": [3, "kg"], "tomato": [6, "pcs"], "carrot": [2, "kg"]} + +# затем создадим две переменные-контейнера и применим метод .items() +for kk, vv in dddd.items(): + print(kk, vv) + +# + +# Помимо этого мы можем вывести только ключи или только +# значения с помощью методов .keys() и .values() соответственно. + +# Предположим, что мы хотим вывести только числа +# (первый элемент значения словаря). + +# возьмем только одну переменную и применим метод .values() +for vvv in dddd.values(): + # значение представляет собой список, выведем его первый элемент + # с индексом [0] + print(vvv[0]) + +# + +# Цикл for можно применить к массиву Numpy. + + +# создадим массив и поместим в переменную number_array +# number_array = np.array([1, 2, 3]) +# +# # пройдемся по нему с помощью цикла for +# for number in number_array: +# print(number) + +# + +# Помимо этого мы можем вложить один цикл for в другой. +# Предположим, что у нас есть следующая база данных клиентов. + +clientss = { + 1: {"name": "Анна", "age": 24, "sex": "male", "revenue": 12000}, + 2: {"name": "Илья", "age": 18, "sex": "female", "revenue": 8000}, +} + +# в первом цикле for поместим id и информацию о клиентах в переменные id и info +for idd, infoo in clientss.items(): + + # выведем id клиента + print("client ID: " + str(idd)) + + # во втором цикле возьмем информацию об очередном клиенте (тоже словарь) + for k12, v12 in infoo.items(): + + # и выведем каждый ключ (название поля) и значение (саму информацию) + print(k12 + ": " + str(v12)) + + # добавим пустую строку после того, как выведем информацию об одном клиенте + print() +# - + +# ### Функции range() и enumerate() +# ### Функция range() + +# создадим последовательность от 0 до 4 +for i in range(5): + print(i) + +# от 1 до 5 +for i in range(1, 6): + print(i) + +# и от 0 до 5 с шагом 2 (то есть будем выводить числа через одно) +for i in range(0, 6, 2): + print(i) + +# Функция range() принимает от одного до трех параметров, +# +# - если передать только один параметр, то мы начнем последовательность с нул +# и закончим на элементе, предшествующем нашему параметру. В примере выше мы +# передали параметр «пять» (range(5)) и получили последовательность 0, 1, 2, +# 3, 4; +# - если указать два параметра, то мы начнем последовательность с первого +# параметра +# и законим на элементе, предшествующем второму параметру. В частности, если +# написать +# range(1, 6), то получится 1, 2, 3, 4, 5; +# - третий параметр устанавливает шаг. По умолчанию он равен единице, однако +# если, +# например, написать, range(0, 6, 2), то мы получим 0, 2, 4. +# +# Что интересно, если совместить range() с функцией len(), то такую +# конструкцию можно использовать для того, чтобы в одном цикле вывести все +# элементы, например, двух списков по их индексу. + +# + +# возьмем месяцы года +months = [ + "Январь", + "Февраль", + "Март", + "Апрель", + "Май", + "Июнь", + "Июль", + "Август", + "Сентябрь", + "Октябрь", + "Ноябрь", + "Декабрь", +] + +# и продажи мороженого в тыс. рублей в каждый из месяцев +sales = [47, 75, 79, 94, 123, 209, 233, 214, 197, 130, 87, 55] + +# задав последовательность через range(len()), +# for i in range(len(months)): + +# мы можем вывести каждый из элементов обоих списков в одном цикле +# print(months[i], sales[i]) + +# + +# Интересно, что по последовательности, создаваемой +# функцией range() можно пройтись и в обратном порядке +# от конца к началу. Сделать это можно тремя способами. +# +# Способ 1. Использовать функцию reversed(). Эта функция +# меняет порядок элементов списка на обратный. + +# создадим список +my_list = [0, 1, 2, 3, 4] + +# передадим его функции reversed() и +# выведем каждый из элементов списка с помощью цикла for +for i in reversed(my_list): + print(i) + +# + +# Одновременно ей можно передать последовательность, создаваемую range() и +# вывести результат в цикле for. + +for i in reversed(range(5)): + print(i) + +# + +# Способ 2. Указать +# в качестве параметра шага. При этом важно, чтобы +# первым параметром указывался конечный элемент списка, +# а вторым — начальный. + +for i in range(4, 0, -1): + print(i) + +print() +# Обратите внимание, что в примере выше 4 входит в +# создаваемую последовательность, а вот 0 уже нет. +# Для того чтобы вывести 0, вторым параметром нужно +# также указать + +for i in range(4, -1, -1): + print(i) + +# + +# Способ 3. Функция sorted(). Наконец, хотя в +# случае это явно не оптимальный вариант, можно +# использовать функцию sorted(), которая +# сортирует элементы списка по убыванию, если +# передать ей параметр reverse = True. + +# создадим последовательность от 0 до 4 +rrr = range(5) + +# отсортируем ее по убыванию +sorted_values = sorted(rrr, reverse=True) + +# выведем элементы отсортированной последовательности +for i in sorted_values: + print(i) +# - + +# ### Функция enumerate() +# +# Мы можем использовать эту функцию, если у нас есть, например, список и, +# проходясь +# в цикле по этому списку, мы хотим также получить порядковый номер (индекс) +# элементов списка. + +# + +# пусть дан список с днями недели +days = [ + "Понедельник", + "Вторник", + "Среда", + "Четверг", + "Пятница", + "Суббота", + "Воскресенье", +] + +# выведем индекс (i) и сами элементы списка (day) +for i, day in enumerate(days): + print(i, day) +# - + +# так же выведем индекс и элементы списка, но начнем с 1 +for i, day in enumerate(days, 1): + print(i, day) + +# ## Цикл while +# +# Цикл выполняется пока верно прописанное в нем условие. + +# + +# зададим начальное значение счетчика +iii = 0 + +# пока счетчик меньше трех +while iii < 3: + + # в каждом цикле будем выводить его текущее значение + print("Текущее значение счетчика: " + str(iii)) + + # внутри цикла не забудем "нарастить" счетчик + iii = iii + 1 + + # и выведем новое значение + print("Новое значение счетчика: " + str(iii)) + + # добавим пустую строку + print() + +# + +# Небольшой лайфхак. Вместо того, чтобы +# писать i = i + 1 Питон позволяет +# использовать короткую запись +# (shorthand operator): i += 1. + +i123 = 0 + +while i123 < 3: + print(i123) + i123 += 1 +# - + +# ### Операторы break и continue +# #### Оператор break + +# + +# вновь возьмем словарь clients +clients1 = { + 1: {"name": "Анна", "age": 24, "sex": "male", "revenue": 12000}, + 2: {"name": "Илья", "age": 18, "sex": "female", "revenue": 8000}, +} + +# в цикле пройдемся по ключам и значениям словаря +for iddd, info1 in clients1.items(): + + # и выведем их + print(iddd, info1) + + # однако уже после первого исполнения цикла, прервем его + break + +# + +# зададим начальное значение счетчика +xxx = 6 + +# будем исполнять цикл пока x не равен нулю +while xxx != 0: + + # выведем текущее значение счетчика + print(xxx) + + # и уменьшим (!) его на 1 + xxx -= 1 + + # если значение счетчика станет равным 3, прервем цикл + if xxx == 3: + break +# - + +# #### Оператор continue + +# с помощью функции range создадим последовательность от 1 до 10 +for i in range(1, 11): + + # если остаток от деления на два не равен нулю (то есть число нечетное) + if i % 2 != 0: + + # идем к следующему числу последовательности + continue + + # в противном случае выводим число + # else: + print(i) + +# ### Форматирование строк в функции print() + +# + +# снова возьмем список с днями недели +days = [ + "Понедельник", + "Вторник", + "Среда", + "Четверг", + "Пятница", + "Суббота", + "Воскресенье", +] + +# и для простоты поместим слово "Понедельник" в переменную Monday +Monday = days[0] +# Monday + +print(f"{Monday} - день тяжелый") + +# То же самое можно сделать с помощью метода .format(). + +# print("{} - день тяжелый".format(Monday)) +# - + +# ## Обобщим сказанное +# Систематизируем пройденное на сегодняшнем занятии. В первой части мы вновь +# обратились к условиям с if и научились +# +# - создавать множественные условия с if-elif-else; +# - вкладывать одно условие в другое; +# - объединять несколько условий с помощью логических операторов and и or; а +# также +# - использовать конструкции if + in и if + not in, чтобы проверить вхождение +# элемента в список или, например, словарь. +# +# Во второй части мы продолжили изучать цикл for и познакомились с циклом +# while. +# Мы узнали, что +# - циклы, как и условия, можно вкладывать один в другой; +# - с помощью функции range() мы можем создавать новую последовательность +# элементов; +# - функция enumerate() создает индекс для существующей последовательности; +# - цикл while выполняется пока верно определенное условие, а чтобы он не стал +# бесконечным, нужно использовать счетчик. +# +# Кроме того, мы узнали, что циклами можно управлять, +# - оператор break позволяет прервать выполнение цикла; +# - оператор continue прерывает выполнение конкретной итерации, но сам цикл +# продолжает исполняться. +# В заключительной части занятия мы узнали, как можно форматировать строковые +# значения и переменные через f-строки и метод .format(). diff --git a/python/makarov/chapter_4_gcollab.ipynb b/python/makarov/chapter_4_gcollab.ipynb new file mode 100644 index 00000000..81dc77b6 --- /dev/null +++ b/python/makarov/chapter_4_gcollab.ipynb @@ -0,0 +1,352 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 27, + "id": "3eb4ccd7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Глава 4. Работа с файлами в Google Colab.'" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Глава 4. Работа с файлами в Google Colab.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "278963ae", + "metadata": {}, + "source": [ + "## Общее описание процесса\n", + "\n", + "В целом работа с файлами в Google Colab состоит\n", + "из следующих этапов.\n", + "\n", + "- Этап 1. Подгрузка файлов с локального компьютера на\n", + "сервер Google.\n", + "- Этап 2. Чтение файла.\n", + "- Этап 3. Построение модели и прогноз.\n", + "- Этап 4. Сохранение результата в новом файле на сервере Google.\n", + "- Этап 5. Скачивание обратно на жесткий диск." + ] + }, + { + "attachments": { + "image-2.png": { + "image/png": "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ELx1SjQUJSMxLR/VDU3XVMsJOAAxXeMQ2yEIxzMzrKgpzEJJlRWe7boi0sd1PsNSV4rConzUeXVFQpgOavnCa6sR9cWZSMx1ILJ7Atr5iJDuDtYOqwmVmTuQnG9EnVleHw282nVHt/YhCPT8he3BqVUOhwN2ux0aDU9FEBERERFdCpYsWtDGgrMpD6jZKhJjKRxqf9gMfaFQKKFwd5gld9blfC5XwTrLVYA2XDzWOscTnW8MzkRERERElxY5OLetptraYMBnAGBoD6XKC1rfBGh8u0LtHe8cVF5doPTsBIVHHBSGWEAXw9BMRERERERE51XbCs5KPaAXYdhnIODd21mrTERERERERHQxtb1kqtAAmlARoKPlJ64yIiIiIiIiooukbVbpyjXNCnZmRURERERERBcf20ITERERERERtYLBmYiIiIiIiKgVDM5ERERERERErWBwJiIiIiIiImoFgzMRERERERFRKxiciYiIiIiIiFrB4ExERERERETUCgZnIiIiIiIiolYwOBMRERERERG1gsGZiIiIiIiIqBUMzkREREREREStYHAmIiIiIiIiagWDMxEREREREVErFAvnzZUkhQoTr5zkLiKilpRKJbRaLRwOB+x2OzQajXsMERERERH9mS1ZtMAVnM1WO/oPGOguJqKWDAYDwsLCnI8ZnImIiIiILh3Hg7PJakPfvv3dxUTUkoeHB8LDw6FQKBiciYiIiIguIXJw5jXORERERERERK1gcCYiIiIiIiJqBYMzERERERERUSsYnImIiIiIiIha0eaDs+QcFM6fRERERERERBdamw7O8j1zLVY7THbAanNAkhifiYiIiIiI6MJq08G5tq4O2w4mY9HBAuzJKkZOZQOqjDY0mCyw2UWQFtMwShMREREREdH51OZrnKvtWhz164uNqu5YlKfC0qQC7EvJRkFFDUw2V02045fUREt2WM0mNBqNMDYNIoBbRQAnIiIiIiIiOhPFwnlzJZPVhr59+7uL2o7KqipszKzEgfArnM8dFhMkmxkqhw2eDYXwN5Whg6cdHUP8EeDrCZ0K0KpVUCmVUCicL3ETwbpyH+Z/swybDuahUSWPlGAP743Rl1+BaQNiYPDQQryc6LQ8PDwQHh4uvlcK2O12aDQa9xgiIiIiIvozW7JoAVQ3/GX6CzaHQ4SCCHdx29FoMuFYZSOKveIg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" + }, + "image.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "e9087e24", + "metadata": {}, + "source": [ + "### Этап 1. Подгрузка файлов в Google Colab\n", + "Если внешние файлы хранятся на локальном компьютере, то нам нужно\n", + "подгрузить их в так называемое «Сессионное хранилище»\n", + "(session storage, по сути, сервер Google).\n", + "\n", + "Подгрузить данные с локального компьютера можно двумя способами.\n", + "\n", + "#### Способ 1. Вручную через вкладку «Файлы»\n", + "Этот способ мы использовали до сих пор. В качестве напоминания приведу\n", + "скриншоты подгрузки файла train.csv.\n", + "\n", + "![image.png](attachment:image.png)\n", + "![image-2.png](attachment:image-2.png)\n", + "\n", + "#### Способ 2. Через объект files библиотеки google.colab" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "e71d86c5", + "metadata": {}, + "outputs": [], + "source": [ + "# К объекту files мы применяем метод .upload(),\n", + "# который\n", + "# передает нам словарь. Ключами этого словаря\n", + "# будут\n", + "# названия файлов, а значениями — сами\n", + "# подгруженные\n", + "# данные. Приведем пример с файлом\n", + "# test.csv.\n", + "#\n", + "# # из библиотеки google.colab импортируем\n", + "# класс files\n", + "# from google.colab import files\n", + "#\n", + "# # создаем объект этого класса, применяем метод .upload()\n", + "# uploaded = files.upload()" + ] + }, + { + "cell_type": "markdown", + "id": "1393d3d5", + "metadata": {}, + "source": [ + "### Этап 2. Чтение файлов\n", + "После загрузки оба файла (train.csv и test.csv) оказываются в\n", + "сессионном хранилище в папке под названием /content/.\n", + "\n", + "### Просмотр содержимого в папке /content/\n", + "\n", + "#### Модуль os и метод .walk()\n", + "Для того чтобы просмотреть ее содержимое внутри блокнота, мы\n", + "можем воспользоваться модулем os (отвечает за взаимодействие\n", + "Питона с операционной системой) и, в частности, методом .walk()\n", + "(позволяет «пройтись» по содержимому конкретной папки)." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "2ee8bf7b", + "metadata": {}, + "outputs": [], + "source": [ + "# # импортируем модуль os\n", + "import os\n", + "\n", + "# выводим пути к папкам (dirpath) и наименования файлов (filenames) и\n", + "# после этого\n", + "for dirpath, _, filenames in os.walk(\"/content/\"):\n", + "\n", + " # во вложенном цикле проходимся по названиям файлов\n", + " for filename in filenames:\n", + "\n", + " # и соединяем путь до папок и входящие в эти папки файлы\n", + " # с помощью метода path.join()\n", + " print(os.path.join(dirpath, filename))" + ] + }, + { + "cell_type": "markdown", + "id": "8522bb66", + "metadata": {}, + "source": [ + "### Команда !ls\n", + "Кроме того, если нас интересуют только видимые файлы и папки,\n", + "мы можем воспользоваться командой !ls (ls означает to list, т.е. «перечислить»)." + ] + }, + { + "cell_type": "markdown", + "id": "a8b909c0", + "metadata": {}, + "source": [ + "### Чтение из переменной uploaded\n", + "\n", + "Основная особенность: информация в объекте bytes представляет\n", + "собой последовательность байтов (byte string), в то время как\n", + "обычная строка — это последовательность символов (character string).\n", + "Компьютер понимает первый тип, мы (люди) — второй." + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "1327a356", + "metadata": {}, + "outputs": [], + "source": [ + "# посмотрим на тип значений словаря uploaded\n", + "# type(uploaded['test.csv'])" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "06bdbc93", + "metadata": {}, + "outputs": [], + "source": [ + "# Таким образом, чтобы прочитать данные напрямую из\n", + "# словаря uploaded, вначале нам нужно преобразовать\n", + "# эти данные в обычную строку.\n", + "\n", + "# обратимся к ключу словаря uploaded и применим\n", + "# метод .decode()\n", + "# uploaded_str = uploaded['test.csv'].decode()\n", + "\n", + "# на выходе получаем обычную строку\n", + "# print(type(uploaded_str))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "ea5cffa8", + "metadata": {}, + "outputs": [], + "source": [ + "# Выведем первые 35 значений.\n", + "\n", + "# print(uploaded_str[:35])\n", + "\n", + "# Если разбить строку методом .split() по символам\n", + "# \\r (возврат к началу строки) и \\n (новая строка),\n", + "# то на выходе мы получим список.\n", + "\n", + "# uploaded_list = uploaded_str.split('\\r\\n')\n", + "# type(uploaded_list)\n", + "\n", + "# Пройдемся по этому списку и выведем первые четыре значения.\n", + "\n", + "# не забудем создать индекс с помощью функции enumerate()\n", + "# for i, line in enumerate(uploaded_list):\n", + "\n", + "# начнем выводить записи\n", + "# print(line)\n", + "\n", + "# когда дойдем до четвертой строки\n", + "# if i == 3:\n", + "\n", + "# прервемся\n", + "# break" + ] + }, + { + "cell_type": "markdown", + "id": "c432fc73", + "metadata": {}, + "source": [ + "### Использование функции open() и конструкции with open()\n", + "Такого же результата можно добиться с помощью базовой функции open().\n", + "\n", + "Функция open() возвращает объект, который используется для чтения и изменения файла. Откроем файл train.csv." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "2c32f504", + "metadata": {}, + "outputs": [], + "source": [ + "# передадим функции open() адрес файла\n", + "# параметр 'r' означает, что мы хотим прочитать (read) файл\n", + "# f1 = open('/content/train.csv', 'r')\n", + "\n", + "# Вначале попробуем применить метод .read().\n", + "\n", + "# метод .read() помещает весь файл в одну строку\n", + "# выведем первые 142 символа (если параметр не указывать, выведется все содержимое)\n", + "# print(f1.read(142))\n", + "\n", + "# в конце файл необходимо закрыть\n", + "# f1.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "9cbf7b8f", + "metadata": {}, + "outputs": [], + "source": [ + "# Для наших целей метод .read() не очень удобен. Будет лучше пройтись по файлу в цикле for.\n", + "\n", + "# снова откроем файл\n", + "# f2 = open('/content/train.csv', 'r')\n", + "#\n", + "# # пройдемся по нашему объекту в цикле for и параллельно создадим индекс\n", + "# for i, line in enumerate(f2):\n", + "#\n", + "# # выведем строки без служебных символов по краям\n", + "# print(line.strip())\n", + "#\n", + "# # дойдя до четвертой строки, прервемся\n", + "# if i == 3:\n", + "# break\n", + "#\n", + "# # не забудем закрыть файл\n", + "# f2.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "952338e4", + "metadata": {}, + "outputs": [], + "source": [ + "# Еще один способ — использовать конструкцию with open(). В этом случае специально закрывать файл не нужно.\n", + "\n", + "# скажем Питону: \"открой файл и назови его f3\"\n", + "# with open(\"/content/test.csv\") as f3:\n", + "#\n", + "# # \"пройдись по строкам без служебных символов\"\n", + "# for i, line in enumerate(f3):\n", + "# print(line.strip())\n", + "#\n", + "# # и \"прервись на четвертой строке\"\n", + "# if i == 3:\n", + "# break" + ] + }, + { + "cell_type": "markdown", + "id": "877b012a", + "metadata": {}, + "source": [ + "### Чтение через библиотеку Pandas\n", + "Вероятно наиболее удобный и подходящий для наших целей способ чтения файлов — это\n", + "преобразование напрямую в датафрейм библиотеки Pandas. С этим методом в целом мы уже знакомы." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "af061737", + "metadata": {}, + "outputs": [], + "source": [ + "# импортируем библиотеку\n", + "# import pandas as pd\n", + "#\n", + "# # применим функцию read_csv() и посмотрим на первые три записи файла train.csv\n", + "# train = pd.read_csv('/content/train.csv')\n", + "# train.head(3)\n", + "#\n", + "# # сделаем то же самое с файлом test.csv\n", + "# test = pd.read_csv('/content/test.csv')\n", + "# test.head(3)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/makarov/chapter_4_gcollab.py b/python/makarov/chapter_4_gcollab.py new file mode 100644 index 00000000..9a99f9cc --- /dev/null +++ b/python/makarov/chapter_4_gcollab.py @@ -0,0 +1,201 @@ +"""Глава 4. + +Работа с файлами в Google Colab. +""" + +# ## Общее описание процесса +# +# В целом работа с файлами в Google Colab состоит +# из следующих этапов. +# +# - Этап 1. Подгрузка файлов с локального компьютера на +# сервер Google. +# - Этап 2. Чтение файла. +# - Этап 3. Построение модели и прогноз. +# - Этап 4. Сохранение результата в новом файле на сервере Google. +# - Этап 5. Скачивание обратно на жесткий диск. + +# ### Этап 1. Подгрузка файлов в Google Colab +# Если внешние файлы хранятся на локальном компьютере, то нам нужно +# подгрузить их в так называемое «Сессионное хранилище» +# (session storage, по сути, сервер Google). +# +# Подгрузить данные с локального компьютера можно двумя способами. +# +# #### Способ 1. Вручную через вкладку «Файлы» +# Этот способ мы использовали до сих пор. В качестве напоминания приведу +# скриншоты подгрузки файла train.csv. +# +# ![image.png](attachment:image.png) +# ![image-2.png](attachment:image-2.png) +# +# #### Способ 2. Через объект files библиотеки google.colab + +# + +# К объекту files мы применяем метод .upload(), +# который +# передает нам словарь. Ключами этого словаря +# будут +# названия файлов, а значениями — сами +# подгруженные +# данные. Приведем пример с файлом +# test.csv. +# +# # из библиотеки google.colab импортируем +# класс files +# from google.colab import files +# +# # создаем объект этого класса, применяем метод .upload() +# uploaded = files.upload() +# - + +# ### Этап 2. Чтение файлов +# После загрузки оба файла (train.csv и test.csv) оказываются в +# сессионном хранилище в папке под названием /content/. +# +# ### Просмотр содержимого в папке /content/ +# +# #### Модуль os и метод .walk() +# Для того чтобы просмотреть ее содержимое внутри блокнота, мы +# можем воспользоваться модулем os (отвечает за взаимодействие +# Питона с операционной системой) и, в частности, методом .walk() +# (позволяет «пройтись» по содержимому конкретной папки). + +# + +# # импортируем модуль os +import os + +# выводим пути к папкам (dirpath) и наименования файлов (filenames) и +# после этого +for dirpath, _, filenames in os.walk("/content/"): + + # во вложенном цикле проходимся по названиям файлов + for filename in filenames: + + # и соединяем путь до папок и входящие в эти папки файлы + # с помощью метода path.join() + print(os.path.join(dirpath, filename)) +# - + +# ### Команда !ls +# Кроме того, если нас интересуют только видимые файлы и папки, +# мы можем воспользоваться командой !ls (ls означает to list, т.е. «перечислить»). + +# ### Чтение из переменной uploaded +# +# Основная особенность: информация в объекте bytes представляет +# собой последовательность байтов (byte string), в то время как +# обычная строка — это последовательность символов (character string). +# Компьютер понимает первый тип, мы (люди) — второй. + +# + +# посмотрим на тип значений словаря uploaded +# type(uploaded['test.csv']) + +# + +# Таким образом, чтобы прочитать данные напрямую из +# словаря uploaded, вначале нам нужно преобразовать +# эти данные в обычную строку. + +# обратимся к ключу словаря uploaded и применим +# метод .decode() +# uploaded_str = uploaded['test.csv'].decode() + +# на выходе получаем обычную строку +# print(type(uploaded_str)) + +# + +# Выведем первые 35 значений. + +# print(uploaded_str[:35]) + +# Если разбить строку методом .split() по символам +# \r (возврат к началу строки) и \n (новая строка), +# то на выходе мы получим список. + +# uploaded_list = uploaded_str.split('\r\n') +# type(uploaded_list) + +# Пройдемся по этому списку и выведем первые четыре значения. + +# не забудем создать индекс с помощью функции enumerate() +# for i, line in enumerate(uploaded_list): + +# начнем выводить записи +# print(line) + +# когда дойдем до четвертой строки +# if i == 3: + +# прервемся +# break +# - + +# ### Использование функции open() и конструкции with open() +# Такого же результата можно добиться с помощью базовой функции open(). +# +# Функция open() возвращает объект, который используется для чтения и изменения файла. Откроем файл train.csv. + +# + +# передадим функции open() адрес файла +# параметр 'r' означает, что мы хотим прочитать (read) файл +# f1 = open('/content/train.csv', 'r') + +# Вначале попробуем применить метод .read(). + +# метод .read() помещает весь файл в одну строку +# выведем первые 142 символа (если параметр не указывать, выведется все содержимое) +# print(f1.read(142)) + +# в конце файл необходимо закрыть +# f1.close() + +# + +# Для наших целей метод .read() не очень удобен. Будет лучше пройтись по файлу в цикле for. + +# снова откроем файл +# f2 = open('/content/train.csv', 'r') +# +# # пройдемся по нашему объекту в цикле for и параллельно создадим индекс +# for i, line in enumerate(f2): +# +# # выведем строки без служебных символов по краям +# print(line.strip()) +# +# # дойдя до четвертой строки, прервемся +# if i == 3: +# break +# +# # не забудем закрыть файл +# f2.close() + +# + +# Еще один способ — использовать конструкцию with open(). В этом случае специально закрывать файл не нужно. + +# скажем Питону: "открой файл и назови его f3" +# with open("/content/test.csv") as f3: +# +# # "пройдись по строкам без служебных символов" +# for i, line in enumerate(f3): +# print(line.strip()) +# +# # и "прервись на четвертой строке" +# if i == 3: +# break +# - + +# ### Чтение через библиотеку Pandas +# Вероятно наиболее удобный и подходящий для наших целей способ чтения файлов — это +# преобразование напрямую в датафрейм библиотеки Pandas. С этим методом в целом мы уже знакомы. + +# + +# импортируем библиотеку +# import pandas as pd +# +# # применим функцию read_csv() и посмотрим на первые три записи файла train.csv +# train = pd.read_csv('/content/train.csv') +# train.head(3) +# +# # сделаем то же самое с файлом test.csv +# test = pd.read_csv('/content/test.csv') +# test.head(3) diff --git a/python/makarov/chapter_5_date.ipynb b/python/makarov/chapter_5_date.ipynb new file mode 100644 index 00000000..1a6dd6fc --- /dev/null +++ b/python/makarov/chapter_5_date.ipynb @@ -0,0 +1,644 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 41, + "id": "08413595", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Глава 5. Дата и время в Питоне.'" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Глава 5. Дата и время в Питоне.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "da7dea7f", + "metadata": {}, + "source": [ + "## Модуль datetime\n", + "\n", + "Первая особенность, про которую стоит сказать, datetime — это\n", + "не только название модуля, но и название одного из классов внутри\n", + "этого модуля. Помимо класса datetime, нас будет интересовать ещё один класс — timedelta.\n", + "\n", + "### Импорт модуля и класса datetime" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "113b1d44", + "metadata": {}, + "outputs": [], + "source": [ + "# импортируем весь модуль\n", + "# import datetime\n", + "\n", + "# вначале создадим объект datetime и передадим ему 19 ноября 2002 года\n", + "from datetime import datetime, timedelta\n", + "\n", + "import pytz\n", + "\n", + "# допустим сейчас 1 января 2070 года\n", + "# Можно импортировать только класс datetime и обращаться непосредственно к нему.\n", + "# from datetime import datetime, timedelta" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef58e788", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2026-04-09 17:33:22.494586\n" + ] + } + ], + "source": [ + "# чтобы получить доступ к функции now(), сначала обратимся к модулю, потом к классу\n", + "print(datetime.now())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f4394dd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2026-04-09 17:33:22.515932\n" + ] + } + ], + "source": [ + "# print(datetime.datetime.now())" + ] + }, + { + "cell_type": "markdown", + "id": "9dcbffda", + "metadata": {}, + "source": [ + "### Объект datetime и функция now()" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "f683a393", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2026-04-09 17:33:22.546502\n", + "2026 4 9 17 33 22 546502\n" + ] + } + ], + "source": [ + "# поместим созданный с помощью функции now() объект datetime в переменную cur_dt\n", + "cur_dt = datetime.now()\n", + "print(cur_dt)\n", + "\n", + "# с помощью соответствующих атрибутов выведем каждый из компонентов объекта\n", + "print(\n", + " cur_dt.year,\n", + " cur_dt.month,\n", + " cur_dt.day,\n", + " cur_dt.hour,\n", + " cur_dt.minute,\n", + " cur_dt.second,\n", + " cur_dt.microsecond,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "0ca6db69", + "metadata": {}, + "source": [ + "Мы также можем посмотреть на день недели, причем в двух форматах.\n", + "Метод .weekday() считает, что неделя начинается с нуля, метод .isoweekday(), что с единицы." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "43565a58", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3 4\n" + ] + } + ], + "source": [ + "print(cur_dt.weekday(), cur_dt.isoweekday())" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "f81cddd7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n", + "2026-04-09 17:33:22.594897+03:00\n" + ] + } + ], + "source": [ + "# посмотрим на часовой пояс с помощью атрибута tzinfo\n", + "print(cur_dt.tzinfo)\n", + "\n", + "# Для того чтобы добавить такую информацию и вывести,\n", + "# например, другой часовой пояс, нам нужно воспользоваться модулем pytz.\n", + "\n", + "\n", + "# выведем текущее время в Москве\n", + "dt_moscow = datetime.now(pytz.timezone(\"Europe/Moscow\"))\n", + "print(dt_moscow)" + ] + }, + { + "cell_type": "markdown", + "id": "8250f9aa", + "metadata": {}, + "source": [ + "## Timestamp\n", + "До сих пор мы работали с привычным для нас делением на годы, месяцы,\n", + "дни, часы, минуты и секунды. При этом компьютеры используют так называемое\n", + "время Unix, которое отсчитывается в секундах c первого января 1970 года." + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "id": "a326a57c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1775745202.614632\n", + "2026-04-09 17:33:22.614632\n" + ] + } + ], + "source": [ + "# получим timestamp текущего времени с помощью метода .timestamp()\n", + "timestamp = datetime.now().timestamp()\n", + "# Посмотрим, сколько секунд и микросекунд прошло с 01.01.1970 и до момента исполнения кода.\n", + "\n", + "print(timestamp)\n", + "\n", + "# для этого воспользуемся методом .fromtimestamp()\n", + "print(datetime.fromtimestamp(timestamp))" + ] + }, + { + "cell_type": "markdown", + "id": "b539b360", + "metadata": {}, + "source": [ + "## Создание объекта datetime вручную\n", + "\n", + "Дату и время не обязательно получать из функции now().\n", + "Мы вполне можем передать объекту datetime наши собственные\n", + "параметры, например, день рождения Питона." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "9bc35c87", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1991-02-20 00:00:00\n", + "1991\n", + "666997200.0\n" + ] + } + ], + "source": [ + "# передадим объекту datetime 20 февраля 1991 года\n", + "hb = datetime(1991, 2, 20)\n", + "print(hb)\n", + "\n", + "# извлечем год с помощью атрибута year\n", + "print(hb.year)\n", + "\n", + "# создадим timestamp\n", + "print(datetime.timestamp(hb))" + ] + }, + { + "cell_type": "markdown", + "id": "eb317d5e", + "metadata": {}, + "source": [ + "## Преобразование строки в datetime и наоборот\n", + "### Строка в datetime через .strptime()\n", + "\n", + "Если дата содержится в строковом формате, Питон не сможет извлечь из нее\n", + "компоненты. Предварительно строку нужно преобразовать. Для этого есть метод .strptime()." + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "db398f31", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2007-12-02 12:30:45\n", + "\n" + ] + } + ], + "source": [ + "# дана строка с датой 2 декабря 2007 года и временем 12 часов 30 минут и 45 секунд\n", + "str_to_dt = \"2007-12-02 12:30:45\"\n", + "type(str_to_dt)\n", + "\n", + "# Преобразуем эту строку в объект datetime с помощью метода .strptime().\n", + "\n", + "res_dt = datetime.strptime(str_to_dt, \"%Y-%m-%d %H:%M:%S\")\n", + "\n", + "print(res_dt)\n", + "print(type(res_dt))" + ] + }, + { + "cell_type": "markdown", + "id": "8f600f37", + "metadata": {}, + "source": [ + "## Datetime в строку через .strftime()\n", + "Обратное преобразование также возможно." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c3d0d02", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Tuesday, November 19, 2002\n", + "\n", + "Tuesday, November 19, 2002\n" + ] + } + ], + "source": [ + "dt_to_str = datetime(2002, 11, 19)\n", + "print(type(dt_to_str))\n", + "\n", + "# преобразуем объект в строку в формате \"день недели, месяц число, год\"\n", + "res_str = datetime.strftime(dt_to_str, \"%A, %B %d, %Y\")\n", + "\n", + "print(res_str)\n", + "print(type(res_str))\n", + "\n", + "# Метод .strftime() можно применять непосредственно к объекту datetime.\n", + "\n", + "print(dt_to_str.strftime(\"%A, %B %d, %Y\"))" + ] + }, + { + "cell_type": "markdown", + "id": "0883ced2", + "metadata": {}, + "source": [ + "## Сравнение и арифметика дат\n", + "### Сравнение дат\n", + "Даты можно сравнивать между собой. Для этого используются стандартные операторы сравнения >, <, >=, <=, ==, !=." + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "id": "35f5f1f6", + "metadata": {}, + "outputs": [], + "source": [ + "# Сравним две даты публикации работ Эйнштейна.\n", + "\n", + "date1 = datetime(1905, 6, 30) # \"К электродинамике движущихся тел\"\n", + "date2 = datetime(1916, 5, 11) # Общая теория относительности\n", + "# Вторая дата должна быть «больше», потому что она более поздняя.\n", + "#\n", + "# date1 < date2\n", + "# True\n", + "# Обратное будет признано ложным.\n", + "#\n", + "# date1 > date2" + ] + }, + { + "cell_type": "markdown", + "id": "3ab01e59", + "metadata": {}, + "source": [ + "### Календарный и алфавитный порядок дат\n", + "\n", + "Интересно, что если даты записаны в виде строки в формате ГГГГ.ММ.ДД,\n", + "то в Питоне мы можем их сравнивать, как если бы мы сравнивали объекты datetime" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "c4424830", + "metadata": {}, + "outputs": [], + "source": [ + "# # вначале запишем даты в виде строки и сравним их\n", + "# '2007-12-02' > '2002-11-19'\n", + "# True\n", + "# # теперь в виде объекта datetime\n", + "# datetime(2007, 12, 2) > datetime(2002, 11, 19)" + ] + }, + { + "cell_type": "markdown", + "id": "295973bf", + "metadata": {}, + "source": [ + "### Промежуток времени и класс timedelta\n" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "a0c3dc97", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3968 days, 0:00:00\n", + "\n" + ] + } + ], + "source": [ + "# Если из большей даты вычесть меньшую, то мы получим временной промежуток между датами.\n", + "\n", + "diff = date2 - date1\n", + "print(diff)\n", + "\n", + "# При этом результат будет храниться в специальном объекте timedelta.\n", + "\n", + "print(type(diff))" + ] + }, + { + "cell_type": "markdown", + "id": "12aaf4de", + "metadata": {}, + "source": [ + "## Арифметика дат\n", + "Объединив объекты datetime и timedelta, мы можем «путешествовать во времени»." + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "id": "f71073ea", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2070-01-01 00:00:00\n", + "1900-02-12 00:00:00\n", + "62092 days, 0:00:00\n" + ] + } + ], + "source": [ + "future = datetime(2070, 1, 1)\n", + "print(future)\n", + "# И мы хотим отправиться в 1 января 1900 года, т.е. на 170 лет назад.\n", + "\n", + "# сначала просто умножим 365 дней на 170\n", + "time_travel = timedelta(days=365) * 170\n", + "\n", + "# а потом переместимся из будущего в прошлое\n", + "past = future - time_travel\n", + "\n", + "# к сожалению, мы немного \"не долетим\", потому что не учли високосные годы, в которых 366 дней\n", + "print(past)\n", + "print(datetime(2070, 1, 1) - datetime(1900, 1, 1))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23c54765", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1900-01-01 00:00:00\n", + "\n", + "Jan 01, 2021\n", + "Jan 02, 2021\n", + "Jan 03, 2021\n", + "Jan 04, 2021\n", + "Jan 05, 2021\n", + "Jan 06, 2021\n", + "Jan 07, 2021\n", + "Jan 08, 2021\n", + "Jan 09, 2021\n", + "Jan 10, 2021\n" + ] + } + ], + "source": [ + "# Теперь снова совершим путешествие во времени, но на этот раз укажем правильное количество дней.\n", + "\n", + "time_travel = timedelta(days=62092)\n", + "\n", + "past = future - time_travel\n", + "print(past)\n", + "# Объект timedelta можно также прибавлять к объекту\n", + "# datetime. Например, нам может быть нужно создать\n", + "# перечень дат, пусть это будут новогодние празники\n", + "# в 2021 году. Для этого удобно использовать цикл while.\n", + "print()\n", + "cur_date = datetime(2021, 1, 1) # эту дату мы будем выводить\n", + "end_date = datetime(2021, 1, 10) # это граница (условие в цикле while)\n", + "\n", + "# пока верно условие\n", + "while cur_date <= end_date:\n", + "\n", + " # выведем cur_date в формате \"месяц число, год\"\n", + " print(cur_date.strftime(\"%b %d, %Y\"))\n", + "\n", + " # прибавим к выводимой дате один день\n", + " cur_date += timedelta(days=1)" + ] + }, + { + "cell_type": "markdown", + "id": "10dcfba8", + "metadata": {}, + "source": [ + "## Дата и обработка ошибок\n", + "### Конструкция try / except и оператор pass\n", + "Прежде чем мы перейдем к практическому примеру с обработкой дат, давайте\n", + "познакомимся с одной полезной конструкцией. Часто мы не уверены, что наш\n", + "код отработает без ошибок. Например, в данных может содержаться неточность, о\n", + "которой мы ничего не знаем. При этом нам не хотелось бы, чтобы исполнение кода остановилось.\n", + "\n", + "Для этого в Питоне есть конструкция try/except." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "012b55d1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "40" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# пусть дан список чисел в строковом формате, и мы хотим посчитать их сумму\n", + "# предположим, буква \"а\" попала в список случайно\n", + "numbers = [\"5\", \"10\", \"a\", \"15\", \"10\"]\n", + "\n", + "# объявим переменную суммы\n", + "total = 0\n", + "\n", + "# пройдемся по числам\n", + "# for number in numbers:\n", + "#\n", + "# # попробуем прибавить число к переменной total\n", + "# try:\n", + "# total += int(number)\n", + "#\n", + "# # если же этого сделать не удастся\n", + "# except:\n", + "# # перейдем к следующему числу\n", + "# pass\n", + "#\n", + "# # выведем сумму\n", + "# total" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee321240", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Элемент 'a' обработать не удалось\n" + ] + }, + { + "data": { + "text/plain": [ + "40" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Оператор pass просто говорит алгоритму продолжить работу. Вместо него можно вывести предупреждение.\n", + "\n", + "total = 0\n", + "\n", + "# for number in numbers:\n", + "# try:\n", + "# total += int(number)\n", + "# except:\n", + "# print(f\"Элемент '{number}' обработать не удалось\")\n", + "#\n", + "# total" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/makarov/chapter_5_date.py b/python/makarov/chapter_5_date.py new file mode 100644 index 00000000..025cf06c --- /dev/null +++ b/python/makarov/chapter_5_date.py @@ -0,0 +1,289 @@ +"""Глава 5. + +Дата и время в Питоне. +""" + +# ## Модуль datetime +# +# Первая особенность, про которую стоит сказать, datetime — это +# не только название модуля, но и название одного из классов внутри +# этого модуля. Помимо класса datetime, нас будет интересовать ещё один +# класс — timedelta. +# +# ### Импорт модуля и класса datetime + +# + +# импортируем весь модуль +# import datetime + +# вначале создадим объект datetime и передадим ему 19 ноября 2002 года +from datetime import datetime, timedelta + +# import pytz + +# допустим сейчас 1 января 2070 года +# Можно импортировать только класс datetime и обращаться непосредственно +# к нему. +# from datetime import datetime, timedelta +# - + +# чтобы получить доступ к функции now(), сначала обратимся к модулю, +# потом к классу +print(datetime.now()) + +# + +# print(datetime.datetime.now()) +# - + +# ### Объект datetime и функция now() + +# + +# поместим созданный с помощью функции now() объект datetime в +# переменную cur_dt +cur_dt = datetime.now() +print(cur_dt) + +# с помощью соответствующих атрибутов выведем каждый из компонентов объекта +print( + cur_dt.year, + cur_dt.month, + cur_dt.day, + cur_dt.hour, + cur_dt.minute, + cur_dt.second, + cur_dt.microsecond, +) +# - + +# Мы также можем посмотреть на день недели, причем в двух форматах. +# Метод .weekday() считает, что неделя начинается с нуля, метод .isoweekday(), +# что с единицы. + +print(cur_dt.weekday(), cur_dt.isoweekday()) + +# + +# посмотрим на часовой пояс с помощью атрибута tzinfo +print(cur_dt.tzinfo) + +# Для того чтобы добавить такую информацию и вывести, +# например, другой часовой пояс, нам нужно воспользоваться модулем pytz. + + +# выведем текущее время в Москве +# dt_moscow = datetime.now(pytz.timezone("Europe/Moscow")) +# print(dt_moscow) +# # - + +# ## Timestamp +# До сих пор мы работали с привычным для нас делением на годы, месяцы, +# дни, часы, минуты и секунды. При этом компьютеры используют так называемое +# время Unix, которое отсчитывается в секундах c первого января 1970 года. + +# + +# получим timestamp текущего времени с помощью метода .timestamp() +timestamp = datetime.now().timestamp() +# Посмотрим, сколько секунд и микросекунд прошло с 01.01.1970 и до момента +# исполнения кода. + +print(timestamp) + +# для этого воспользуемся методом .fromtimestamp() +print(datetime.fromtimestamp(timestamp)) +# - + +# ## Создание объекта datetime вручную +# +# Дату и время не обязательно получать из функции now(). +# Мы вполне можем передать объекту datetime наши собственные +# параметры, например, день рождения Питона. + +# + +# передадим объекту datetime 20 февраля 1991 года +hb = datetime(1991, 2, 20) +print(hb) + +# извлечем год с помощью атрибута year +print(hb.year) + +# создадим timestamp +print(datetime.timestamp(hb)) +# - + +# ## Преобразование строки в datetime и наоборот +# ### Строка в datetime через .strptime() +# +# Если дата содержится в строковом формате, Питон не сможет извлечь из нее +# компоненты. Предварительно строку нужно преобразовать. Для этого есть метод +# strptime(). + +# + +# дана строка с датой 2 декабря 2007 года и временем 12 часов 30 минут и 45 +# секунд +str_to_dt = "2007-12-02 12:30:45" +type(str_to_dt) + +# Преобразуем эту строку в объект datetime с помощью метода .strptime(). + +res_dt = datetime.strptime(str_to_dt, "%Y-%m-%d %H:%M:%S") + +print(res_dt) +print(type(res_dt)) +# - + +# ## Datetime в строку через .strftime() +# Обратное преобразование также возможно. + +# + +dt_to_str = datetime(2002, 11, 19) +print(type(dt_to_str)) + +# преобразуем объект в строку в формате "день недели, месяц число, год" +res_str = datetime.strftime(dt_to_str, "%A, %B %d, %Y") + +print(res_str) +print(type(res_str)) + +# Метод .strftime() можно применять непосредственно к объекту datetime. + +print(dt_to_str.strftime("%A, %B %d, %Y")) +# - + +# ## Сравнение и арифметика дат +# ### Сравнение дат +# Даты можно сравнивать между собой. Для этого используются стандартные +# операторы сравнения >, <, >=, <=, ==, !=. + +# + +# Сравним две даты публикации работ Эйнштейна. + +date1 = datetime(1905, 6, 30) # "К электродинамике движущихся тел" +date2 = datetime(1916, 5, 11) # Общая теория относительности +# Вторая дата должна быть «больше», потому что она более поздняя. +# +# date1 < date2 +# True +# Обратное будет признано ложным. +# +# date1 > date2 +# - + +# ### Календарный и алфавитный порядок дат +# +# Интересно, что если даты записаны в виде строки в формате ГГГГ.ММ.ДД, +# то в Питоне мы можем их сравнивать, как если бы мы сравнивали объекты +# datetime + +# + +# # вначале запишем даты в виде строки и сравним их +# '2007-12-02' > '2002-11-19' +# True +# # теперь в виде объекта datetime +# datetime(2007, 12, 2) > datetime(2002, 11, 19) +# - + +# ### Промежуток времени и класс timedelta +# + +# + +# Если из большей даты вычесть меньшую, то мы получим временной промежуток +# между датами. + +diff = date2 - date1 +print(diff) + +# При этом результат будет храниться в специальном объекте timedelta. + +print(type(diff)) +# - + +# ## Арифметика дат +# Объединив объекты datetime и timedelta, мы можем «путешествовать во времени». + +# + +future = datetime(2070, 1, 1) +print(future) +# И мы хотим отправиться в 1 января 1900 года, т.е. на 170 лет назад. + +# сначала просто умножим 365 дней на 170 +time_travel = timedelta(days=365) * 170 + +# а потом переместимся из будущего в прошлое +past = future - time_travel + +# к сожалению, мы немного "не долетим", потому что не учли високосные годы, в +# которых 366 дней +print(past) +print(datetime(2070, 1, 1) - datetime(1900, 1, 1)) + +# + +# Теперь снова совершим путешествие во времени, но на этот раз укажем +# правильное количество дней. + +time_travel = timedelta(days=62092) + +past = future - time_travel +print(past) +# Объект timedelta можно также прибавлять к объекту +# datetime. Например, нам может быть нужно создать +# перечень дат, пусть это будут новогодние праздники +# в 2021 году. Для этого удобно использовать цикл while. +print() +cur_date = datetime(2021, 1, 1) # эту дату мы будем выводить +end_date = datetime(2021, 1, 10) # это граница (условие в цикле while) + +# пока верно условие +while cur_date <= end_date: + + # выведем cur_date в формате "месяц число, год" + print(cur_date.strftime("%b %d, %Y")) + + # прибавим к выводимой дате один день + cur_date += timedelta(days=1) +# - + +# ## Дата и обработка ошибок +# ### Конструкция try / except и оператор pass +# Прежде чем мы перейдем к практическому примеру с обработкой дат, давайте +# познакомимся с одной полезной конструкцией. Часто мы не уверены, что наш +# код отработает без ошибок. Например, в данных может содержаться неточность, о +# которой мы ничего не знаем. При этом нам не хотелось бы, чтобы исполнение +# кода остановилось. +# +# Для этого в Питоне есть конструкция try/except. + +# + +# пусть дан список чисел в строковом формате, и мы хотим посчитать их сумму +# предположим, буква "а" попала в список случайно +numbers = ["5", "10", "a", "15", "10"] + +# объявим переменную суммы +total = 0 + +# пройдемся по числам +# for number in numbers: +# +# # попробуем прибавить число к переменной total +# try: +# total += int(number) +# +# # если же этого сделать не удастся +# except: +# # перейдем к следующему числу +# pass +# +# # выведем сумму +# total + +# + +# Оператор pass просто говорит алгоритму продолжить работу. Вместо него можно +# вывести предупреждение. + +total = 0 + +# for number in numbers: +# try: +# total += int(number) +# except: +# print(f"Элемент '{number}' обработать не удалось") +# +# total diff --git a/python/makarov/chapter_6_func.ipynb b/python/makarov/chapter_6_func.ipynb new file mode 100644 index 00000000..2032bd7d --- /dev/null +++ b/python/makarov/chapter_6_func.ipynb @@ -0,0 +1,2081 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"Функции в Питоне.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0AoPSXyUTTLc" + }, + "source": [ + "## Функции в Питоне" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "W3QeADnwrI_g" + }, + "source": [ + "### Встроенные функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mmuSaN9wrMpL" + }, + "outputs": [], + "source": [ + "from collections.abc import ItemsView\n", + "from typing import Callable\n", + "\n", + "# импортируем библиотеки\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# перед вызовом функции нужно не забыть импортировать\n", + "# соответствующую библиотеку\n", + "import numpy as np\n", + "\n", + "# установим точку отсчета\n", + "np.random.seed(42)\n", + "# и снова сгенерируем данные о росте\n", + "# (как мы делали на восьмом занятии вводного курса)\n", + "height = list(np.round(np.random.normal(180, 10, 1000)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4R42tP5dJflr" + }, + "source": [ + "#### Параметры и аргументы функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 430 + }, + "id": "GZzCE-GXsD8H", + "outputId": "0a6e6454-e150-48b1-bc92-e54be971a738" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAIm5JREFUeJzt3XtwVOXh//FP7hDIJg2QLBlCBC9c5CICjVsppZLJhRRB0hmhqOBQGGliB+I1FkG0841aqlYGoToKOhWrzAhy0VTkksgQUCgMghgBsYDJBgWT5SIhIc/vj/440xUwCSTsk837NXNm2HOenDzPHGPeOdndhBhjjAAAACwSGugJAAAA/BiBAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA64YGewOWor69XeXm5YmJiFBISEujpAACARjDG6MSJE0pKSlJo6E/fI2mVgVJeXq7k5ORATwMAAFyGw4cPq1u3bj85plUGSkxMjKT/LtDlcgV4NgAAoDF8Pp+Sk5Od7+M/pVUGyvlf67hcLgIFAIBWpjFPz+BJsgAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsE54oCcAoGVd8+iaQE+hyb5+OjvQUwAQYNxBAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHUIFAAAYB0CBQAAWIdAAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHUIFAAAYB0CBQAAWIdAAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHWaFCiFhYUaOnSoYmJilJCQoLFjx6qsrMxvzIgRIxQSEuK33XfffX5jDh06pOzsbEVHRyshIUEPPfSQ6urqrnw1AAAgKIQ3ZXBxcbFyc3M1dOhQ1dXV6bHHHlN6ero+//xzdejQwRk3depUPfnkk87j6Oho59/nzp1Tdna23G63Nm/erIqKCt1zzz2KiIjQ//3f/zXDkgAAQGvXpEApKirye7xkyRIlJCRo+/btGj58uLM/Ojpabrf7ouf48MMP9fnnn+ujjz5SYmKibrrpJj311FN65JFH9MQTTygyMvIylgEAAILJFT0Hpbq6WpIUHx/vt//NN99U586d1a9fPxUUFOj06dPOsdLSUvXv31+JiYnOvoyMDPl8Pu3Zs+ein6empkY+n89vAwAAwatJd1D+V319vWbMmKFbb71V/fr1c/b/7ne/U0pKipKSkrRr1y498sgjKisr07vvvitJ8nq9fnEiyXns9Xov+rkKCws1d+7cy50qAABoZS47UHJzc7V7925t2rTJb/+0adOcf/fv319du3bVyJEjdeDAAV177bWX9bkKCgqUn5/vPPb5fEpOTr68iQMAAOtd1q948vLytHr1am3YsEHdunX7ybGpqamSpP3790uS3G63Kisr/cacf3yp561ERUXJ5XL5bQAAIHg1KVCMMcrLy9Py5cu1fv169ejRo8GP2blzpySpa9eukiSPx6PPPvtMR48edcasXbtWLpdLffv2bcp0AABAkGrSr3hyc3O1dOlSvffee4qJiXGeMxIbG6v27dvrwIEDWrp0qUaNGqVOnTpp165dmjlzpoYPH64BAwZIktLT09W3b1/dfffdevbZZ+X1ejVr1izl5uYqKiqq+VcIAABanSbdQVm4cKGqq6s1YsQIde3a1dnefvttSVJkZKQ++ugjpaenq3fv3nrggQeUk5OjVatWOecICwvT6tWrFRYWJo/Ho7vuukv33HOP3/umAACAtq1Jd1CMMT95PDk5WcXFxQ2eJyUlRe+//35TPjUAAGhD+Fs8AADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKwTHugJAK3JNY+uCfQUAKBN4A4KAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA64QHegIA8GPXPLom0FNosq+fzg70FICgwh0UAABgHQIFAABYh0ABAADWIVAAAIB1CBQA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# теперь построим гистограмму передав ей два параметра,\n", + "# данные о росте и количество интервалов\n", + "# первый параметр у нас позиционный, второй - именованный\n", + "plt.hist(height, bins=10)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 430 + }, + "id": "If9utZiWZYeq", + "outputId": "47fde034-9efb-4986-ce67-ae2bf202e257" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAIm5JREFUeJzt3XtwVOXh//FP7hDIJg2QLBlCBC9c5CICjVsppZLJhRRB0hmhqOBQGGliB+I1FkG0841aqlYGoToKOhWrzAhy0VTkksgQUCgMghgBsYDJBgWT5SIhIc/vj/440xUwCSTsk837NXNm2HOenDzPHGPeOdndhBhjjAAAACwSGugJAAAA/BiBAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA64YGewOWor69XeXm5YmJiFBISEujpAACARjDG6MSJE0pKSlJo6E/fI2mVgVJeXq7k5ORATwMAAFyGw4cPq1u3bj85plUGSkxMjKT/LtDlcgV4NgAAoDF8Pp+Sk5Od7+M/pVUGyvlf67hcLgIFAIBWpjFPz+BJsgAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsE54oCcAoGVd8+iaQE+hyb5+OjvQUwAQYNxBAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHUIFAAAYB0CBQAAWIdAAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHUIFAAAYB0CBQAAWIdAAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHWaFCiFhYUaOnSoYmJilJCQoLFjx6qsrMxvzIgRIxQSEuK33XfffX5jDh06pOzsbEVHRyshIUEPPfSQ6urqrnw1AAAgKIQ3ZXBxcbFyc3M1dOhQ1dXV6bHHHlN6ero+//xzdejQwRk3depUPfnkk87j6Oho59/nzp1Tdna23G63Nm/erIqKCt1zzz2KiIjQ//3f/zXDkgAAQGvXpEApKirye7xkyRIlJCRo+/btGj58uLM/Ojpabrf7ouf48MMP9fnnn+ujjz5SYmKibrrpJj311FN65JFH9MQTTygyMvIylgEAAILJFT0Hpbq6WpIUHx/vt//NN99U586d1a9fPxUUFOj06dPOsdLSUvXv31+JiYnOvoyMDPl8Pu3Zs+ein6empkY+n89vAwAAwatJd1D+V319vWbMmKFbb71V/fr1c/b/7ne/U0pKipKSkrRr1y498sgjKisr07vvvitJ8nq9fnEiyXns9Xov+rkKCws1d+7cy50qAABoZS47UHJzc7V7925t2rTJb/+0adOcf/fv319du3bVyJEjdeDAAV177bWX9bkKCgqUn5/vPPb5fEpOTr68iQMAAOtd1q948vLytHr1am3YsEHdunX7ybGpqamSpP3790uS3G63Kisr/cacf3yp561ERUXJ5XL5bQAAIHg1KVCMMcrLy9Py5cu1fv169ejRo8GP2blzpySpa9eukiSPx6PPPvtMR48edcasXbtWLpdLffv2bcp0AABAkGrSr3hyc3O1dOlSvffee4qJiXGeMxIbG6v27dvrwIEDWrp0qUaNGqVOnTpp165dmjlzpoYPH64BAwZIktLT09W3b1/dfffdevbZZ+X1ejVr1izl5uYqKiqq+VcIAABanSbdQVm4cKGqq6s1YsQIde3a1dnefvttSVJkZKQ++ugjpaenq3fv3nrggQeUk5OjVatWOecICwvT6tWrFRYWJo/Ho7vuukv33HOP3/umAACAtq1Jd1CMMT95PDk5WcXFxQ2eJyUlRe+//35TPjUAAGhD+Fs8AADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKwTHugJAK3JNY+uCfQUAKBN4A4KAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA64QHegIA8GPXPLom0FNosq+fzg70FICgwh0UAABgHQIFAABYh0ABAADWIVAAAIB1CBQA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# первый параметр можно также сделать именованным (данные обозначаются через x)\n", + "# и тогда порядок параметров можно менять\n", + "plt.hist(bins=10, x=height)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 430 + }, + "id": "5rM2p7inZ4gh", + "outputId": "da7b573e-eaea-437a-8400-6d9cf7c44da5" + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAigAAAGdCAYAAAA44ojeAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAIm5JREFUeJzt3XtwVOXh//FP7hDIJg2QLBlCBC9c5CICjVsppZLJhRRB0hmhqOBQGGliB+I1FkG0841aqlYGoToKOhWrzAhy0VTkksgQUCgMghgBsYDJBgWT5SIhIc/vj/440xUwCSTsk837NXNm2HOenDzPHGPeOdndhBhjjAAAACwSGugJAAAA/BiBAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA64YGewOWor69XeXm5YmJiFBISEujpAACARjDG6MSJE0pKSlJo6E/fI2mVgVJeXq7k5ORATwMAAFyGw4cPq1u3bj85plUGSkxMjKT/LtDlcgV4NgAAoDF8Pp+Sk5Od7+M/pVUGyvlf67hcLgIFAIBWpjFPz+BJsgAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsE54oCcAoGVd8+iaQE+hyb5+OjvQUwAQYNxBAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHUIFAAAYB0CBQAAWIdAAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHUIFAAAYB0CBQAAWIdAAQAA1iFQAACAdQgUAABgHQIFAABYh0ABAADWIVAAAIB1CBQAAGAdAgUAAFiHQAEAANYhUAAAgHWaFCiFhYUaOnSoYmJilJCQoLFjx6qsrMxvzIgRIxQSEuK33XfffX5jDh06pOzsbEVHRyshIUEPPfSQ6urqrnw1AAAgKIQ3ZXBxcbFyc3M1dOhQ1dXV6bHHHlN6ero+//xzdejQwRk3depUPfnkk87j6Oho59/nzp1Tdna23G63Nm/erIqKCt1zzz2KiIjQ//3f/zXDkgAAQGvXpEApKirye7xkyRIlJCRo+/btGj58uLM/Ojpabrf7ouf48MMP9fnnn+ujjz5SYmKibrrpJj311FN65JFH9MQTTygyMvIylgEAAILJFT0Hpbq6WpIUHx/vt//NN99U586d1a9fPxUUFOj06dPOsdLSUvXv31+JiYnOvoyMDPl8Pu3Zs+ein6empkY+n89vAwAAwatJd1D+V319vWbMmKFbb71V/fr1c/b/7ne/U0pKipKSkrRr1y498sgjKisr07vvvitJ8nq9fnEiyXns9Xov+rkKCws1d+7cy50qAABoZS47UHJzc7V7925t2rTJb/+0adOcf/fv319du3bVyJEjdeDAAV177bWX9bkKCgqUn5/vPPb5fEpOTr68iQMAAOtd1q948vLytHr1am3YsEHdunX7ybGpqamSpP3790uS3G63Kisr/cacf3yp561ERUXJ5XL5bQAAIHg1KVCMMcrLy9Py5cu1fv169ejRo8GP2blzpySpa9eukiSPx6PPPvtMR48edcasXbtWLpdLffv2bcp0AABAkGrSr3hyc3O1dOlSvffee4qJiXGeMxIbG6v27dvrwIEDWrp0qUaNGqVOnTpp165dmjlzpoYPH64BAwZIktLT09W3b1/dfffdevbZZ+X1ejVr1izl5uYqKiqq+VcIAABanSbdQVm4cKGqq6s1YsQIde3a1dnefvttSVJkZKQ++ugjpaenq3fv3nrggQeUk5OjVatWOecICwvT6tWrFRYWJo/Ho7vuukv33HOP3/umAACAtq1Jd1CMMT95PDk5WcXFxQ2eJyUlRe+//35TPjUAAGhD+Fs8AADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKwTHugJAK3JNY+uCfQUAKBN4A4KAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA6xAoAADAOgQKAACwDoECAACsQ6AAAADrECgAAMA6BAoAALAOgQIAAKxDoAAAAOsQKAAAwDoECgAAsA6BAgAArEOgAAAA64QHegIA8GPXPLom0FNosq+fzg70FICgwh0UAABgHQIFAABYh0ABAADWIVAAAIB1CBQA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# у параметра bins есть аргумент по умолчанию (как раз 10 интервалов),\n", + "# а значит, этот параметр можно не указывать\n", + "plt.hist(height)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "t6UAoUmwag2c", + "outputId": "ef4a2fe2-25e4-4cb4-de2d-e55464101797" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Первая строка\n", + "\n", + "Третья строка\n" + ] + } + ], + "source": [ + "# функция может не принимать параметров\n", + "print(\"Первая строка\")\n", + "print()\n", + "print(\"Третья строка\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-QM-A2zzJhIn" + }, + "source": [ + "#### Функции и методы" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "o_fZPD7XJjFy", + "outputId": "80d76b59-0838-44a2-a700-873b19e9e02f" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Machine Learning'" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# дана строка\n", + "some_string = \"machine learning\"\n", + "\n", + "# применим метод .title()\n", + "some_string.title()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 176 + }, + "id": "uVPQU3PoKwpR", + "outputId": "72d66e92-3184-4c44-a758-651f7f13b9a7" + }, + "outputs": [], + "source": [ + "# к списку\n", + "some_list: list[str] = [\"machine\", \"learning\"]\n", + "\n", + "# этот метод не применить\n", + "# some_list.title()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lIM5gFo4TbUg" + }, + "source": [ + "### Собственные функции в Питоне" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CgGpEK0AwM2k" + }, + "source": [ + "#### Объявление и вызов функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IjjLVSbWqDpE" + }, + "outputs": [], + "source": [ + "# создадим функцию, которая удваивает любое передаваемое ей значение\n", + "\n", + "\n", + "def double(x_arg: int) -> int:\n", + " \"\"\"Умножает переданное число на 2.\"\"\"\n", + " res = x_arg * 2\n", + " return res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "EW6-h1F8ufBG", + "outputId": "115c5e57-2e1c-4102-ff92-ddade6454602" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# и вызовем ее, передав число 2\n", + "double(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mS-C-sJePhVf" + }, + "source": [ + "#### Пустое тело функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "40pnqSnoTR0Z" + }, + "outputs": [], + "source": [ + "# тело функции не может быть пустым\n", + "\n", + "\n", + "def only_return() -> None:\n", + " \"\"\"Функция с одним return.\"\"\"\n", + " # нужно либо указать ключевое слово return\n", + " return" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HuYLHkX7TZnt" + }, + "outputs": [], + "source": [ + "only_return()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tihYzRyawYD8" + }, + "outputs": [], + "source": [ + "# либо оператор pass\n", + "\n", + "\n", + "# def only_pass() -> None:\n", + "# \"\"\"Функция ничего не делает.\"\"\"\n", + "# pass" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dP_fIG04TLad" + }, + "outputs": [], + "source": [ + "# only_pass()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "u06oHGCNK6Rm", + "outputId": "48a7322c-cc8c-455f-f8a3-445c9619b9c7" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "# такая функция вернет тип данных None (отсутствие значения)\n", + "# print(only_return()) -> None" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "08Pbq-5VREZk" + }, + "source": [ + "#### Функция print() вместо return" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Jaj1wdaAYFF-" + }, + "outputs": [], + "source": [ + "# можно использовать print(), но есть нюансы (см. на странице урока)\n", + "\n", + "\n", + "def double_print(x_arg: int) -> None:\n", + " \"\"\"Функция умножает переданное число на 2 и выводит результат в консоль.\"\"\"\n", + " res = x_arg * 2\n", + " print(res)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XgtVgq_HYKyh", + "outputId": "53140a9c-9829-4d6c-dcd9-863b9811b037" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10\n" + ] + } + ], + "source": [ + "double_print(5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zmJv5y8dLUJK" + }, + "source": [ + "#### Параметры собственных функций" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uhOnVbWhuis_" + }, + "outputs": [], + "source": [ + "# объявим функцию с параметрами x и y\n", + "\n", + "\n", + "def calc_sum(x_arg: int, y_arg: int) -> int:\n", + " \"\"\"Функция складывает два целых числа.\"\"\"\n", + " # и выведем их сумму\n", + " return x_arg + y_arg" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "KTEhuHaYwWLQ", + "outputId": "2e3085e6-fe3c-456b-d4a0-e7e9a3ad46ac" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вызовем эту функцию с одним позиционным и одним именованным параметром\n", + "calc_sum(1, y_arg=2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "baCYb7BbT46W", + "outputId": "a46fc104-cdc3-49cc-ec5c-1ccd7894905f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# параметрам функции можно задать аргументы по умолчанию\n", + "\n", + "\n", + "def calc_sum_default(x_arg: int = 1, y_arg: int = 2) -> int:\n", + " \"\"\"Функция складывает два целых числа.\"\"\"\n", + " return x_arg + y_arg\n", + "\n", + "\n", + "# и при вызове тогда их указывать не обязательно\n", + "calc_sum_default()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2DQF4G9w_JUW", + "outputId": "96859e9d-1785-4d78-81f2-9f2b19ccb072" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Some string\n" + ] + } + ], + "source": [ + "# функция может не иметь параметров\n", + "\n", + "\n", + "def print_string() -> None:\n", + " \"\"\"Функция выводит строку 'Some string'.\"\"\"\n", + " print(\"Some string\")\n", + "\n", + "\n", + "print_string()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jZABsfhPx9wd" + }, + "source": [ + "#### Аннотация функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "TAoI_kYPyB44" + }, + "outputs": [], + "source": [ + "# укажем, что на входе функция принимает тип float, а возвращает int\n", + "# значение 3,5 - это значение параметра x по умолчанию\n", + "\n", + "\n", + "def f(x_arg: float = 3.5) -> int:\n", + " \"\"\"Функция приводит переданный float-аргумент к целочисленному типу.\"\"\"\n", + " return int(x_arg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "QaNrg6kZyW8Y", + "outputId": "4afa6d5c-eaa7-4651-e9c1-aa704dd19f3e" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'x': float, 'return': int}" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# желаемый тип данных можно посмотреть через атрибут __annotations__\n", + "f.__annotations__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-iKjBO501oYJ", + "outputId": "d6e6c8d3-89c3-4d12-9979-f323f45b82c4" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вызовем функцию без параметров\n", + "f()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ziFM30EY2Auj" + }, + "outputs": [], + "source": [ + "# сохраним аннотации, но изменим суть функции\n", + "# def f(x: float) -> int:\n", + "# # теперь вместо int она будет возвращать float\n", + "# return float(x)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "AdpR-rb92Qmn", + "outputId": "e5f3fb8c-5172-46e2-af70-ccfedce19921" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3.0" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вновь вызовем функцию, передав ей на входе int, и ожидая на выходе получить float\n", + "f(3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vlOHQZGZ_ESX" + }, + "source": [ + "#### Дополнительные возможности" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "QittQ3qiK8S4", + "outputId": "8b2c99f0-f61d-4fe5-e015-22c1762ddea6" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вызов функции можно совмещать с арифметическими\n", + "result = calc_sum(1, 2) * 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "83RysL9MMQCw", + "outputId": "45598627-36e6-47f3-d456-9e650ba74450" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# и логическими операциями\n", + "result = calc_sum(1, 2) > 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "YL1UrXNFb84A", + "outputId": "395474c0-41a3-4146-a978-2e450c2ab8b7" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'P'" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# можно и так\n", + "\n", + "\n", + "def first_letter() -> str:\n", + " \"\"\"Функция возвращает строку 'Python'.\"\"\"\n", + " return \"Python\"\n", + "\n", + "\n", + "print(first_letter()[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "WC59uMaoWy8u", + "outputId": "6773f697-f6b8-4cf9-edaa-3ddcff1ac057" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Введите число: 5\n" + ] + }, + { + "data": { + "text/plain": [ + "25" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# функция может не принимать параметров, но использовать input()\n", + "\n", + "\n", + "def use_input() -> int:\n", + " \"\"\"Функция возводит введенное число в квадрат.\"\"\"\n", + " # запросим у пользователя число и переведем его в тип данных int\n", + " user_inp = int(input(\"Введите число: \"))\n", + "\n", + " # возведем число в квадрат\n", + " result_pow = user_inp**2\n", + "\n", + " # вернем результат\n", + " return result_pow\n", + "\n", + "\n", + "# вызовем функцию\n", + "use_input()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7L2W-41oM6vK" + }, + "source": [ + "#### Результат вызова функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "zVLZODr-PazE", + "outputId": "af00da71-633a-4b23-c7ce-ed29d5ee7234" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[0, 1, 2, 3, 4]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# функция может возвращать также список, кортеж, словарь и др.\n", + "\n", + "\n", + "# объявим функцию, которая на входе получает число,\n", + "# а на выходе формирует список чисел от 0 и до числа, предшествующего заданному\n", + "def create_list(x_arg: int) -> list[int]:\n", + " \"\"\"Создает список,заполненный числами от 0 до x_arg.\"\"\"\n", + " # создадим пустой список\n", + " my_list: list[int] = []\n", + "\n", + " # в цикле for создадим последовательность\n", + " for index in range(x_arg):\n", + "\n", + " # и поместим ее в список\n", + " my_list.append(index)\n", + "\n", + " return my_list\n", + "\n", + "\n", + "# результатом вызова этой функции будет список\n", + "create_list(5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RI4Xl_CHNm3B" + }, + "outputs": [], + "source": [ + "# функция может возвращать сразу два значения\n", + "\n", + "\n", + "def tuple_f() -> tuple[str, int]:\n", + " \"\"\"Возвращает кортеж ('python', 42).\"\"\"\n", + " string = \"Python\"\n", + " x_arg = 42\n", + " return string, x_arg" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "e4AXnLEdNzMJ", + "outputId": "c34bf598-3e76-4128-96ca-494dc144bea1" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Python 42\n", + " \n" + ] + } + ], + "source": [ + "# если использовать две переменные\n", + "a_var, b_var = tuple_f()\n", + "\n", + "# на выходе мы получим строку и число\n", + "print(a_var, b_var)\n", + "print(type(a_var), type(b_var))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "n89-CN1pSlgP", + "outputId": "02b74687-471c-4a3e-e59c-c26440d25189" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('Python', 42)\n", + "\n" + ] + } + ], + "source": [ + "# если одну\n", + "c_var = tuple_f()\n", + "\n", + "# получится кортеж\n", + "print(c_var)\n", + "print(type(c_var))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bQzEDji5VFCY", + "outputId": "a9131375-4436-46a5-d27b-cc982a1ac1df" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# выводом может быть логическое значение (True или False)\n", + "\n", + "\n", + "def is_divisible(x_arg: int) -> bool:\n", + " \"\"\"Функция проверяет, является ли число четным.\"\"\"\n", + " # если остаток от деления на два равен нулю\n", + " if x_arg % 2 == 0:\n", + " # вернем True\n", + " return True\n", + "\n", + " # в противном случае False\n", + " return False\n", + "\n", + "\n", + "is_divisible(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uRNLyptXUoyj" + }, + "source": [ + "#### Использование библиотек" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gFTdRnLlUt4Y" + }, + "outputs": [], + "source": [ + "# применим функцию mean() библиотеки Numpy для расчета среднего арифметического\n", + "\n", + "\n", + "# на входе наша функция примет список или массив x,\n", + "def mean_f(x_arg: list[int]) -> float:\n", + " \"\"\"Функция вычисляет среднее и прибавляет 1 к результату.\"\"\"\n", + " # рассчитает среднее арифметическое и прибавит единицу\n", + " return float(np.mean(x_arg) + 1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "OFeR_QpWU4i1", + "outputId": "a4f13201-904f-47c1-d97d-cc3d84598450" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3.0" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# и подготовить данные\n", + "x_var: list[int] = [1, 2, 3]\n", + "\n", + "mean_f(x_var)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kY91ANMfXeRG" + }, + "source": [ + "#### Глобальные и локальные переменные" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "a4HSsRlBVBT2" + }, + "outputs": [], + "source": [ + "# создадим глобальную переменную вне функции\n", + "global_name = \"Петр\"\n", + "\n", + "# а затем используем ее внутри новой функции\n", + "\n", + "\n", + "def show_name() -> None:\n", + " \"\"\"Функция выводит в консоль глобальную переменную global_name.\"\"\"\n", + " print(global_name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "_trqrh-zTjkk", + "outputId": "a436b20d-c6cf-42c2-c21a-f1ad43a70c91" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Петр\n" + ] + } + ], + "source": [ + "show_name()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jmStHPcqTo3F" + }, + "outputs": [], + "source": [ + "# а теперь вначале создадим функцию,\n", + "# внутри которой объявим локальную переменную\n", + "\n", + "\n", + "def show_local_name() -> None:\n", + " \"\"\"Функция выводит в консоль 'Алена'.\"\"\"\n", + " local_name_1 = \"Алена\"\n", + " print(local_name_1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "9KMmXhAIUJkT", + "outputId": "19f7a460-1ba2-4b13-e72a-b25a74d4543a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Алена\n" + ] + } + ], + "source": [ + "show_local_name()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 159 + }, + "id": "mcINdfP0UYt9", + "outputId": "352fad89-c4e3-49c7-a74f-64b0fb5192aa" + }, + "outputs": [], + "source": [ + "# при попытке обратиться к переменной вне функции мы получим ошибку\n", + "# local_name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GfAMDzGvUcZ8" + }, + "outputs": [], + "source": [ + "# превратить локальную переменную в глобальную можно\n", + "# через ключевое слово global\n", + "local_name = \"Татьяна\"\n", + "\n", + "\n", + "def make_global() -> None:\n", + " \"\"\"Создает глобальную переменную local_name и выводит ее в консоль.\"\"\"\n", + " global local_name # pylint: disable=W0603\n", + " local_name = \"Алена\"\n", + " print(local_name)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "glXQZMD9UpDf", + "outputId": "97d5d26f-7f28-4611-f6f7-006866a20068" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Алена\n" + ] + } + ], + "source": [ + "make_global()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "GSHkMhwXUxQK", + "outputId": "adda3989-248e-4c4e-8a41-0ed373aa4820" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Алена'" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# теперь ошибки быть не должно\n", + "# local_name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "rDAqC_PlZr35" + }, + "outputs": [], + "source": [ + "# объявим глобальную переменную\n", + "global_number = 5\n", + "\n", + "\n", + "def print_number() -> None:\n", + " \"\"\"Выводит в консоль значение локальной переменной local_number.\"\"\"\n", + " # затем объявим локальную переменную\n", + " local_number = 10\n", + " print(\"Local number:\", local_number)\n", + " print(\"Global number:\", global_number)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JvOjd91fGILS", + "outputId": "d7753061-9c05-49f6-c7d9-59fd4f299b30" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Local number: 10\n" + ] + } + ], + "source": [ + "# функция всегда \"предпочтет\" локальную переменную\n", + "print_number()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "306Y9HOWGIOf", + "outputId": "41ec6f6a-5d13-4412-e844-e63767eda086" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Global number: 5\n" + ] + } + ], + "source": [ + "# при этом значение глобальной переменной для остального кода не изменится\n", + "print(\"Global number:\", global_number)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xLJn10TGXhlq" + }, + "source": [ + "### Lambda-функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CFPwBvbYXrYR", + "outputId": "4b879d40-03cc-4851-df11-29a92136f043" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим функцию, которая принимает два числа и перемножает их\n", + "lf: Callable[[int, int], int] = lambda a_arg, b_arg: a_arg * b_arg\n", + "\n", + "# вызовем функцию и передадим ей числа 2 и 3\n", + "lf(2, 3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "65xVovHHXks9", + "outputId": "d3bdc43a-fed4-4f65-bb86-4dc388694488" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# этот же функционал можно поместить в обычную функцию\n", + "\n", + "\n", + "def normal_f(a_arg: int, b_arg: int) -> int:\n", + " \"\"\"Возвращает произведение переданных аргументов.\"\"\"\n", + " return a_arg * b_arg\n", + "\n", + "\n", + "normal_f(2, 3)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "na0O4KAlE1Pk" + }, + "source": [ + "#### Lambda-функция внутри функции filter()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RMNawYCas6ER", + "outputId": "0ccd1139-a50f-491c-f44b-43d8602f3c26" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[15, 27, 18]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим список\n", + "nums_list: list[int] = [15, 27, 9, 18, 3, 1, 4]\n", + "\n", + "# напишем lambda-функцию, которая выведет True,\n", + "# если число больше 10, и False, если меньше\n", + "is_more_then_10: Callable[[int], bool] = lambda n_arg: n_arg > 10\n", + "\n", + "# поместим список и lambda-функцию в функцию filter()\n", + "# и преобразуем результат в список\n", + "list(filter(is_more_then_10, nums_list))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Y86jO6CewXnU", + "outputId": "c380fd97-b591-4f5b-b9ca-e1c504d5cc49" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[15, 27, 18]" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# все это можно записать в одну строчку\n", + "list(filter(lambda n_arg: n_arg > 10, nums_list))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VWAYPtGg0YQh", + "outputId": "9a81b80a-52c4-46c3-8bc1-07a445561738" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[15, 27, 18]" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# ту же задачу можно решить через обычную функцию,\n", + "# но придется написать больше кода\n", + "\n", + "\n", + "def is_more_then_10_2(n_arg: int) -> bool:\n", + " \"\"\"Функция проверяет, больше ли переданное число 10.\"\"\"\n", + " if n_arg > 10:\n", + " return True\n", + "\n", + " return False\n", + "\n", + "\n", + "list(filter(is_more_then_10_2, nums_list))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "k9aPF9yVE9eF" + }, + "source": [ + "#### Lambda-функция внутри функции sorted()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "dMFSmXtJYb39", + "outputId": "20eb2b83-cad8-4fc5-fc11-fcbca0ea3725" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[(901, 0.0), (1002, 0.22982440568634488), (442, 0.25401128310081567)]" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# напомню, что мы создали список из кортежей,\n", + "# и в каждом кортеже был индекс фильма и расстояние до него\n", + "indices_distances = [\n", + " (901, 0.0),\n", + " (1002, 0.22982440568634488),\n", + " (442, 0.25401128310081567),\n", + "]\n", + "\n", + "# lambda-функция возьмет каждый кортеж и вернет второй [1] его элемент\n", + "# передав эту функцию через параметр key, мы отсортируем список по расстоянию\n", + "sorted(indices_distances, key=lambda x_arg: x_arg[1], reverse=False)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "C8bwJf2oLI69" + }, + "source": [ + "#### Немедленно вызываемые функции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XjbG4yHOK9in", + "outputId": "178e510d-4aac-4ef5-b663-8b527bfb333d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "100" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# lambda-функцию можно вызвать сразу в момент объявления\n", + "(lambda x_arg: x_arg * x_arg)(10) # pylint: disable=C3002" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pgeY1tf6U9PP" + }, + "source": [ + "### \\*args и \\**kwargs" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uCX_-CWeYJeZ" + }, + "source": [ + "#### \\*args" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QxlLBRqLW0Mu" + }, + "outputs": [], + "source": [ + "# напишем функцию для расчета среднего арифметического двух чисел\n", + "\n", + "\n", + "def mean_simple(a_arg: int, b_arg: int) -> float:\n", + " \"\"\"Функция вычисляет среднее арифметическое.\"\"\"\n", + " return (a_arg + b_arg) / 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "EhuFz8wpXBVr", + "outputId": "db2f6e0a-3c22-464a-f071-2f8817d3b936" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1.5" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mean_simple(1, 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cyQLlIZLVIM3" + }, + "outputs": [], + "source": [ + "# объявим функцию, которой нужно передать список\n", + "\n", + "\n", + "def mean_1(list_arg: list[int]) -> float:\n", + " \"\"\"Функция вычисляет среднее арифметическое переданного массива чисел.\"\"\"\n", + " # зададим переменную для суммы,\n", + " total = 0\n", + "\n", + " # в цикле сложим все числа из списка\n", + " for num in list_arg:\n", + " total += num\n", + "\n", + " # и разделим на количество элементов\n", + " return total / len(list_arg)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nh7pebndVIQU", + "outputId": "1436f42d-4a15-4d13-d917-bad885b440df" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2.5" + ] + }, + "execution_count": 62, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим список\n", + "list_: list[int] = [1, 2, 3, 4]\n", + "\n", + "# и передадим его в новую функцию\n", + "mean_1(list_)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 159 + }, + "id": "zy8lFJA9bkBc", + "outputId": "5311a807-f945-4c29-9422-adafa172e940" + }, + "outputs": [], + "source": [ + "# однако новая функция уже не может работать с отдельными числами\n", + "# mean(1, 2) -> Error" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vwrIY7CqVIYO" + }, + "outputs": [], + "source": [ + "# объявим функцию с *args\n", + "\n", + "\n", + "def mean_2(*nums: int) -> float:\n", + " \"\"\"Функция вычисляет среднее арифметическое переданного массива чисел.\"\"\"\n", + " # в данном случае мы складываем элементы кортежа\n", + " total = 0\n", + " for num in nums:\n", + " total += num\n", + "\n", + " return total / len(nums)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "P5Q1bhIVXz9p", + "outputId": "137523e1-03c8-49d5-ad5e-445879480dbf" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2.5" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# теперь мы можем передать функции отдельные числа\n", + "mean_2(1, 2, 3, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bhHgfAZ-Ytmp", + "outputId": "a13075ac-6eef-4c70-b02b-fdd68cdf6be4" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2.5" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# или список\n", + "mean_2(*list_)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "L3NKa556r5O0", + "outputId": "7523137c-3f2c-419c-81c0-3573b02993b0" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 2, 3, 4) \n" + ] + } + ], + "source": [ + "# убедимся, что оператор распаковки * формирует кортеж\n", + "\n", + "\n", + "def test_type(*nums: int) -> None:\n", + " \"\"\"Функция проверят тип аргумента *nums.\"\"\"\n", + " print(nums, type(nums))\n", + "\n", + "\n", + "test_type(1, 2, 3, 4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XHDvzgXFxql2", + "outputId": "05e55975-5e49-4bff-b0ee-e1fa91dad322" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(1, 2, 3, 4) \n" + ] + } + ], + "source": [ + "# со списком происходит то же самое\n", + "test_type(*list_)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "JeLoABCMy_om", + "outputId": "3f00f8a2-8801-456a-9341-df12e3753e1d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2, 3, 4, 5, 6]\n" + ] + } + ], + "source": [ + "# для наглядности приведем еще один пример\n", + "a_list: list[int] = [1, 2, 3]\n", + "b_list: list[int] = [*a_list, 4, 5, 6]\n", + "\n", + "print(b_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qh8xqKMwYLpH" + }, + "source": [ + "#### \\**kwargs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gzEpZF_13Vfq" + }, + "outputs": [], + "source": [ + "# **kwargs преобразует именованные параметры в словарь\n", + "\n", + "\n", + "def fn(**kwargs: int) -> ItemsView[str, int]:\n", + " \"\"\"Возвращает список пар ключ/значение именованных параметров.\"\"\"\n", + " return kwargs.items()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rl4dALTK3plJ", + "outputId": "c317ee78-c259-4cff-cd33-110d73749b74" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_items([('a', 1), ('b', 2)])" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fn(a=1, b=2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Zd930nvoasfs" + }, + "outputs": [], + "source": [ + "# *nums превращается в кортеж, **params - в словарь\n", + "\n", + "\n", + "def simple_stats(*nums: int, **params: bool) -> None:\n", + " \"\"\"Функция вычисляет среднее арифметическое и СКО.\"\"\"\n", + " # если ключ 'mean' есть в словаре params и его значение == True\n", + " if \"mean\" in params and params[\"mean\"] is True:\n", + "\n", + " # рассчитаем среднее арифметическое и округлим\n", + " # \\t - это символ табуляции\n", + " print(f\"mean: \\t{np.round(np.mean(nums), 3)}\")\n", + "\n", + " # если ключ 'std' есть в словаре params и его значение == True\n", + " if \"std\" in params and params[\"std\"] is True:\n", + "\n", + " # рассчитаем СКО и округлим\n", + " print(f\"std: \\t{np.round(np.std(nums), 3)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "YQqRLpXvfYJZ", + "outputId": "d5a72bf9-363d-4204-e659-5d61c414ea88" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mean: \t12.5\n", + "std: \t5.59\n" + ] + } + ], + "source": [ + "# вызовем функцию simple_stats() и передадим ей числа и именованные аргументы\n", + "simple_stats(5, 10, 15, 20, mean=True, std=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "h5VyRzsjn2ny", + "outputId": "a6762112-09d1-495c-f2e8-1b62fea3e20b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mean: \t12.5\n" + ] + } + ], + "source": [ + "# если для одного из параметров задать значение False,\n", + "# функция не выведет соответствующую метрику\n", + "simple_stats(5, 10, 15, 20, mean=True, std=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "J6TjmWJ3hbBv", + "outputId": "21d40d7d-9493-496c-86ac-2064f4b5b1a3" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mean: \t12.5\n", + "std: \t5.59\n" + ] + } + ], + "source": [ + "# если мы хотим передать параметры списком и словарем,\n", + "list_nums: list[int] = [5, 10, 15, 20]\n", + "settings: dict[str, bool] = {\"mean\": True, \"std\": True}\n", + "\n", + "# то нам нужно использовать операторы распаковки * и ** соответственно\n", + "simple_stats(*list_nums, **settings)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "55FDFsesoAOP", + "outputId": "0c09c820-dc81-4d04-d4e0-ce9ab1b1a1ea" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "mean: \t12.5\n", + "std: \t5.59\n" + ] + } + ], + "source": [ + "# ничто не мешает нам добавить еще один параметр\n", + "simple_stats(5, 10, 15, 20, mean=True, std=True, median=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j4mcGPUgjKp4" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/python/makarov/chapter_6_func.py b/python/makarov/chapter_6_func.py new file mode 100644 index 00000000..e87d4bc7 --- /dev/null +++ b/python/makarov/chapter_6_func.py @@ -0,0 +1,633 @@ +"""Функции в Питоне.""" + +# ## Функции в Питоне + +# ### Встроенные функции + +# + +from collections.abc import ItemsView +from typing import Callable + +import matplotlib.pyplot as plt + +# импортируем библиотеки +import numpy as np + +# перед вызовом функции нужно не забыть импортировать +# соответствующую библиотеку + +# установим точку отсчета +np.random.seed(42) +# и снова сгенерируем данные о росте +# (как мы делали на восьмом занятии вводного курса) +height = list(np.round(np.random.normal(180, 10, 1000))) +# - + +# #### Параметры и аргументы функции + +# теперь построим гистограмму передав ей два параметра, +# данные о росте и количество интервалов +# первый параметр у нас позиционный, второй - именованный +plt.hist(height, bins=10) +plt.show() + +# первый параметр можно также сделать именованным (данные обозначаются через x) +# и тогда порядок параметров можно менять +plt.hist(bins=10, x=height) +plt.show() + +# у параметра bins есть аргумент по умолчанию (как раз 10 интервалов), +# а значит, этот параметр можно не указывать +plt.hist(height) +plt.show() + +# функция может не принимать параметров +print("Первая строка") +print() +print("Третья строка") + +# #### Функции и методы + +# + +# дана строка +some_string = "machine learning" + +# применим метод .title() +some_string.title() + +# + +# к списку +some_list: list[str] = ["machine", "learning"] + +# этот метод не применить +# some_list.title() +# - + +# ### Собственные функции в Питоне + +# #### Объявление и вызов функции + +# + +# создадим функцию, которая удваивает любое передаваемое ей значение + + +def double(x_arg: int) -> int: + """Умножает переданное число на 2.""" + res = x_arg * 2 + return res + + +# - + +# и вызовем ее, передав число 2 +double(2) + +# #### Пустое тело функции + +# + +# тело функции не может быть пустым + + +def only_return() -> None: + """Функция с одним return.""" + # нужно либо указать ключевое слово return + return + + +# - + +only_return() + +# + +# либо оператор pass + + +# def only_pass() -> None: +# """Функция ничего не делает.""" +# pass + +# + +# only_pass() + +# + +# такая функция вернет тип данных None (отсутствие значения) +# print(only_return()) -> None +# - + +# #### Функция print() вместо return + +# + +# можно использовать print(), но есть нюансы (см. на странице урока) + + +def double_print(x_arg: int) -> None: + """Функция умножает переданное число на 2 и выводит результат в консоль.""" + res = x_arg * 2 + print(res) + + +# - + +double_print(5) + +# #### Параметры собственных функций + +# + +# объявим функцию с параметрами x и y + + +def calc_sum(x_arg: int, y_arg: int) -> int: + """Функция складывает два целых числа.""" + # и выведем их сумму + return x_arg + y_arg + + +# - + +# вызовем эту функцию с одним позиционным и одним именованным параметром +calc_sum(1, y_arg=2) + +# + +# параметрам функции можно задать аргументы по умолчанию + + +def calc_sum_default(x_arg: int = 1, y_arg: int = 2) -> int: + """Функция складывает два целых числа.""" + return x_arg + y_arg + + +# и при вызове тогда их указывать не обязательно +calc_sum_default() + +# + +# функция может не иметь параметров + + +def print_string() -> None: + """Функция выводит строку 'Some string'.""" + print("Some string") + + +print_string() +# - + +# #### Аннотация функции + +# + +# укажем, что на входе функция принимает тип float, а возвращает int +# значение 3,5 - это значение параметра x по умолчанию + + +def f(x_arg: float = 3.5) -> int: + """Функция приводит переданный float-аргумент к целочисленному типу.""" + return int(x_arg) + + +# - + +# желаемый тип данных можно посмотреть через атрибут __annotations__ +# f.__annotations__ + +# вызовем функцию без параметров +f() + +# + +# сохраним аннотации, но изменим суть функции +# def f(x: float) -> int: +# # теперь вместо int она будет возвращать float +# return float(x) +# - + +# вновь вызовем функцию, передав ей на входе int, и ожидая на выходе +# получить float +f(3) + +# #### Дополнительные возможности + +# вызов функции можно совмещать с арифметическими +result = calc_sum(1, 2) * 2 + +# и логическими операциями +result = calc_sum(1, 2) > 2 + +# + +# можно и так + + +def first_letter() -> str: + """Функция возвращает строку 'Python'.""" + return "Python" + + +print(first_letter()[0]) + +# + +# функция может не принимать параметров, но использовать input() + + +def use_input() -> int: + """Функция возводит введенное число в квадрат.""" + # запросим у пользователя число и переведем его в тип данных int + user_inp = int(input("Введите число: ")) + + # возведем число в квадрат + result_pow = user_inp**2 + + # вернем результат + return result_pow + + +# вызовем функцию +use_input() +# - + +# #### Результат вызова функции + +# + +# функция может возвращать также список, кортеж, словарь и др. + + +# объявим функцию, которая на входе получает число, +# а на выходе формирует список чисел от 0 и до числа, предшествующего заданному +def create_list(x_arg: int) -> list[int]: + """Создает список,заполненный числами от 0 до x_arg.""" + # создадим пустой список + my_list: list[int] = [] + + # в цикле for создадим последовательность + for index in range(x_arg): + + # и поместим ее в список + my_list.append(index) + + return my_list + + +# результатом вызова этой функции будет список +create_list(5) + +# + +# функция может возвращать сразу два значения + + +def tuple_f() -> tuple[str, int]: + """Возвращает кортеж ('python', 42).""" + string = "Python" + x_arg = 42 + return string, x_arg + + +# + +# если использовать две переменные +a_var, b_var = tuple_f() + +# на выходе мы получим строку и число +print(a_var, b_var) +print(type(a_var), type(b_var)) + +# + +# если одну +c_var = tuple_f() + +# получится кортеж +print(c_var) +print(type(c_var)) + +# + +# выводом может быть логическое значение (True или False) + + +def is_divisible(x_arg: int) -> bool: + """Функция проверяет, является ли число четным.""" + # если остаток от деления на два равен нулю + if x_arg % 2 == 0: + # вернем True + return True + + # в противном случае False + return False + + +is_divisible(10) +# - + +# #### Использование библиотек + +# + +# применим функцию mean() библиотеки Numpy для расчета среднего арифметического + + +# на входе наша функция примет список или массив x, +def mean_f(x_arg: list[int]) -> float: + """Функция вычисляет среднее и прибавляет 1 к результату.""" + # рассчитает среднее арифметическое и прибавит единицу + return float(np.mean(x_arg) + 1) + + +# + +# и подготовить данные +x_var: list[int] = [1, 2, 3] + +mean_f(x_var) +# - + +# #### Глобальные и локальные переменные + +# + +# создадим глобальную переменную вне функции +global_name = "Петр" + +# а затем используем ее внутри новой функции + + +def show_name() -> None: + """Функция выводит в консоль глобальную переменную global_name.""" + print(global_name) + + +# - + +show_name() + +# + +# а теперь вначале создадим функцию, +# внутри которой объявим локальную переменную + + +def show_local_name() -> None: + """Функция выводит в консоль 'Алена'.""" + local_name_1 = "Алена" + print(local_name_1) + + +# - + +show_local_name() + +# + +# при попытке обратиться к переменной вне функции мы получим ошибку +# local_name + +# + +# превратить локальную переменную в глобальную можно +# через ключевое слово global +local_name = "Татьяна" + + +def make_global() -> None: + """Создает глобальную переменную local_name и выводит ее в консоль.""" + global local_name # pylint: disable=W0603 + local_name = "Алена" + print(local_name) + + +# - + +make_global() + +# + +# теперь ошибки быть не должно +# local_name + +# + +# объявим глобальную переменную +global_number = 5 + + +def print_number() -> None: + """Выводит в консоль значение локальной переменной local_number.""" + # затем объявим локальную переменную + local_number = 10 + print("Local number:", local_number) + print("Global number:", global_number) + + +# - + +# функция всегда "предпочтет" локальную переменную +print_number() + +# при этом значение глобальной переменной для остального кода не изменится +print("Global number:", global_number) + +# ### Lambda-функции + +# + +# создадим функцию, которая принимает два числа и перемножает их +lf: Callable[[int, int], int] = lambda a_arg, b_arg: a_arg * b_arg + +# вызовем функцию и передадим ей числа 2 и 3 +lf(2, 3) + +# + +# этот же функционал можно поместить в обычную функцию + + +def normal_f(a_arg: int, b_arg: int) -> int: + """Возвращает произведение переданных аргументов.""" + return a_arg * b_arg + + +normal_f(2, 3) +# - + +# #### Lambda-функция внутри функции filter() + +# + +# создадим список +nums_list: list[int] = [15, 27, 9, 18, 3, 1, 4] + +# напишем lambda-функцию, которая выведет True, +# если число больше 10, и False, если меньше +is_more_then_10: Callable[[int], bool] = lambda n_arg: n_arg > 10 + +# поместим список и lambda-функцию в функцию filter() +# и преобразуем результат в список +list(filter(is_more_then_10, nums_list)) +# - + +# все это можно записать в одну строчку +list(filter(lambda n_arg: n_arg > 10, nums_list)) + +# + +# ту же задачу можно решить через обычную функцию, +# но придется написать больше кода + + +def is_more_then_10_2(n_arg: int) -> bool: + """Функция проверяет, больше ли переданное число 10.""" + if n_arg > 10: + return True + + return False + + +list(filter(is_more_then_10_2, nums_list)) +# - + +# #### Lambda-функция внутри функции sorted() + +# + +# напомню, что мы создали список из кортежей, +# и в каждом кортеже был индекс фильма и расстояние до него +indices_distances = [ + (901, 0.0), + (1002, 0.22982440568634488), + (442, 0.25401128310081567), +] + +# lambda-функция возьмет каждый кортеж и вернет второй [1] его элемент +# передав эту функцию через параметр key, мы отсортируем список по расстоянию +sorted(indices_distances, key=lambda x_arg: x_arg[1], reverse=False) +# - + +# #### Немедленно вызываемые функции + +# lambda-функцию можно вызвать сразу в момент объявления +(lambda x_arg: x_arg * x_arg)(10) # pylint: disable=C3002 + +# ### \*args и \**kwargs + +# #### \*args + +# + +# напишем функцию для расчета среднего арифметического двух чисел + + +def mean_simple(a_arg: int, b_arg: int) -> float: + """Функция вычисляет среднее арифметическое.""" + return (a_arg + b_arg) / 2 + + +# - + +mean_simple(1, 2) + +# + +# объявим функцию, которой нужно передать список + + +def mean_1(list_arg: list[int]) -> float: + """Функция вычисляет среднее арифметическое переданного массива чисел.""" + # зададим переменную для суммы, + total = 0 + + # в цикле сложим все числа из списка + for num in list_arg: + total += num + + # и разделим на количество элементов + return total / len(list_arg) + + +# + +# создадим список +list_: list[int] = [1, 2, 3, 4] + +# и передадим его в новую функцию +mean_1(list_) + +# + +# однако новая функция уже не может работать с отдельными числами +# mean(1, 2) -> Error + +# + +# объявим функцию с *args + + +def mean_2(*nums: int) -> float: + """Функция вычисляет среднее арифметическое переданного массива чисел.""" + # в данном случае мы складываем элементы кортежа + total = 0 + for num in nums: + total += num + + return total / len(nums) + + +# - + +# теперь мы можем передать функции отдельные числа +mean_2(1, 2, 3, 4) + +# или список +mean_2(*list_) + +# + +# убедимся, что оператор распаковки * формирует кортеж + + +def test_type(*nums: int) -> None: + """Функция проверят тип аргумента *nums.""" + print(nums, type(nums)) + + +test_type(1, 2, 3, 4) +# - + +# со списком происходит то же самое +test_type(*list_) + +# + +# для наглядности приведем еще один пример +a_list: list[int] = [1, 2, 3] +b_list: list[int] = [*a_list, 4, 5, 6] + +print(b_list) +# - + +# #### \**kwargs + +# + +# **kwargs преобразует именованные параметры в словарь + + +def fn(**kwargs: int) -> ItemsView[str, int]: + """Возвращает список пар ключ/значение именованных параметров.""" + return kwargs.items() + + +# - + +fn(a=1, b=2) + +# + +# *nums превращается в кортеж, **params - в словарь + + +def simple_stats(*nums: int, **params: bool) -> None: + """Функция вычисляет среднее арифметическое и СКО.""" + # если ключ 'mean' есть в словаре params и его значение == True + if "mean" in params and params["mean"] is True: + + # рассчитаем среднее арифметическое и округлим + # \t - это символ табуляции + print(f"mean: \t{np.round(np.mean(nums), 3)}") + + # если ключ 'std' есть в словаре params и его значение == True + if "std" in params and params["std"] is True: + + # рассчитаем СКО и округлим + print(f"std: \t{np.round(np.std(nums), 3)}") + + +# - + +# вызовем функцию simple_stats() и передадим ей числа и именованные аргументы +simple_stats(5, 10, 15, 20, mean=True, std=True) + +# если для одного из параметров задать значение False, +# функция не выведет соответствующую метрику +simple_stats(5, 10, 15, 20, mean=True, std=False) + +# + +# если мы хотим передать параметры списком и словарем, +list_nums: list[int] = [5, 10, 15, 20] +settings: dict[str, bool] = {"mean": True, "std": True} + +# то нам нужно использовать операторы распаковки * и ** соответственно +simple_stats(*list_nums, **settings) +# - + +# ничто не мешает нам добавить еще один параметр +simple_stats(5, 10, 15, 20, mean=True, std=True, median=True) diff --git a/python/makarov/chapter_7_oop.ipynb b/python/makarov/chapter_7_oop.ipynb new file mode 100644 index 00000000..ae3a9926 --- /dev/null +++ b/python/makarov/chapter_7_oop.ipynb @@ -0,0 +1,922 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 22, + "id": "ef26197a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Глава 7. ООП. Классы и объекты.'" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"Глава 7. ООП. Классы и объекты.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "495585ae", + "metadata": {}, + "source": [ + "## Понятие объектно-ориентированного программирования\n", + "Отвлечемся на секунду от программирования. Представьте себе, что вам\n", + "нужно нарисовать множество фигурок кошек. Хотя все кошки разные, у них все же есть нечто общее:\n", + "\n", + "- во-первых, у них есть общие свойства, например, шерсть, когти и хвост;\n", + "- кроме того, любая кошка может выполнять определенные действия: лазить по деревьям, мяукать и потягиваться.\n", + "\n", + "Так вот объектно-ориентированное программирование предполагает, что вначале мы\n", + "создаем шаблон нужного нам предмета (назовем его классом, class), а затем на\n", + "основе шаблона создаем конкретный предмет (назовем его объектом, object).\n", + "\n", + "## Классы и объекты в Питоне\n", + "### Создание класса и метод .__init__()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d8cdbd9", + "metadata": {}, + "outputs": [], + "source": [ + "# создадим класс CatClass\n", + "class CatClassv1:\n", + " \"\"\"Класс для представления кошки.\"\"\"\n", + "\n", + " # и пропишем метод .__init__()\n", + " def __init__(self):\n", + " \"\"\"Инициализация объекта класса.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "c1d10bcb", + "metadata": {}, + "source": [ + "### Создание объекта" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb1f8134", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "__main__.CatClass" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим объект Matroskin класса CatClass\n", + "matroskin = CatClassv1()\n", + "\n", + "# проверим тип данных созданной переменной\n", + "type(matroskin)" + ] + }, + { + "cell_type": "markdown", + "id": "d84c0731", + "metadata": {}, + "source": [ + "### Атрибуты класса" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "291e15d2", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('gray', 'cat')" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вновь создадим класс CatClass\n", + "class CatClassv2:\n", + " \"\"\"Класс для представления кошки.\"\"\"\n", + "\n", + " # метод .__init__() на этот раз принимает еще и параметр color\n", + "\n", + " def __init__(self, color):\n", + " \"\"\"Инициализация объекта класса.\"\"\"\n", + " # этот параметр будет записан в переменную атрибута с таким же названием\n", + " self.color = color\n", + "\n", + " # значение атрибута type_ задается внутри класса\n", + " self.type_ = \"cat\"\n", + "\n", + "\n", + "# повторно создадим объект класса CatClass, передав ему параметр цвета шерсти\n", + "matroskin = CatClassv2(\"gray\")\n", + "\n", + "# и выведем атрибуты класса\n", + "matroskin.color, matroskin.type_" + ] + }, + { + "cell_type": "markdown", + "id": "f1ac88de", + "metadata": {}, + "source": [ + "### Методы класса" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f393dce", + "metadata": {}, + "outputs": [], + "source": [ + "# перепишем класс CatClass\n", + "class CatClassv11:\n", + " \"\"\"Класс для представления кошки.\"\"\"\n", + "\n", + " # метод .__init__() и атрибуты оставим без изменений\n", + "\n", + " def __init__(self, color):\n", + " \"\"\"Инициализация объекта класса.\"\"\"\n", + " self.color = color\n", + " self.type_ = \"cat\"\n", + "\n", + " # однако добавим метод, который позволит коту мяукать\n", + " def meow(self):\n", + " \"\"\"Метод класса, голос объекта.\"\"\"\n", + " for i in range(3):\n", + " print(\"Мяу\", i)\n", + "\n", + " # и метод .info() для вывода информации об объекте\n", + " def info(self):\n", + " \"\"\"Метод класса, информация об объекте.\"\"\"\n", + " print(self.color, self.type_)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "103eafa0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Мяу\n", + "Мяу\n", + "Мяу\n", + "\n", + "gray cat\n" + ] + } + ], + "source": [ + "# создадим объект\n", + "matroskin = CatClassv11(\"gray\")\n", + "print()\n", + "# применим метод .meow()\n", + "matroskin.meow()\n", + "print()\n", + "# и метод .info()\n", + "matroskin.info()" + ] + }, + { + "cell_type": "markdown", + "id": "c6e7ddb7", + "metadata": {}, + "source": [ + "## Принципы объектно-ориентированного программирования\n", + "### Инкапсуляция\n", + "Инкапсуляция (encapsulation) — это способность класса хранить данные\n", + "и методы внутри себя. Другими словами, объект класса можно представить \n", + "в виде капсулы, в которой содержатся необходимые данные и методы.\n", + "\n", + "## Публичные и частные атрибуты класса\n", + "С понятием инкапсуляции тесно связаны понятия публичных и частных\n", + "атрибутов (public and private attributes). Публичные атрибуты — это те\n", + "атрибуты, к которым можно получить доступ за пределами «капсулы» класса.\n", + "\n", + "*По умолчанию все атрибуты в Питоне публичные.*\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8a21af7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'dog'" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# изменим атрибут type_ объекта Matroskin на dog\n", + "matroskin.type_ = \"dog\"\n", + "\n", + "# выведем этот атрибут\n", + "matroskin.type_\n", + "\n", + "# Согласитесь, это не очень разумно. Нам бы хотелось,\n", + "# чтобы объекты класса CatClass не изменяли значения\n", + "# атрибута type_. Другими словами, нам нужно сделать\n", + "# этот атрибут частным. Здесь есть два способа:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71ee32dd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'dog'" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Способ 1.\n", + "class CatClassv12:\n", + " \"\"\"Поставить один символ подчеркивания перед атрибутом.\"\"\"\n", + "\n", + " def __init__(self, color):\n", + " \"\"\"Инициализация.\"\"\"\n", + " self.color = color\n", + " # символ подчеркивания ПЕРЕД названием атрибута указывает,\n", + " # что это частный атрибут и изменять его не стоит\n", + " self._type_ = \"cat\"\n", + "\n", + "\n", + "# это лишь частично решает проблему\n", + "\n", + "\n", + "# вновь создадим объект класса CatClass\n", + "# Matroskin = CatClass(\"gray\")\n", + "#\n", + "# # и изменим значение атрибута _type_\n", + "# Matroskin._type_ = \"dog\"\n", + "# Matroskin._type_" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35699a80", + "metadata": {}, + "outputs": [], + "source": [ + "# Способ 2.\n", + "class CatClassv13:\n", + " \"\"\"Поставить перед названием атрибута __.\"\"\"\n", + "\n", + " def __init__(self, color):\n", + " \"\"\"Инициализация.\"\"\"\n", + " self.color = color\n", + " # символ двойного подчеркивания предотвратит доступ извне\n", + " # self.__type_ = \"cat\"\n", + "\n", + "\n", + "# Matroskin = CatClass('gray')\n", + "#\n", + "# # теперь при вызове этого атрибута Питон выдаст ошибку\n", + "# Matroskin.\n", + "# выведет ошибку\n", + "\n", + "# К сожалению, и это ограничение можно обойти, поставив\n", + "# _НазваниеКласса перед атрибутом.\n", + "\n", + "# поставим _CatClass перед __type_,\n", + "# изменим значение атрибута и\n", + "# Matroskin._CatClass__type_ = 'dog'\n", + "#\n", + "# # выведем его\n", + "# Matroskin._CatClass__type_" + ] + }, + { + "cell_type": "markdown", + "id": "a5227ae7", + "metadata": {}, + "source": [ + "### Наследование\n", + "Принцип *наследования* (inheritance) предполагает, что один класс наследует\n", + "атрибуты и методы другого. В этом случае, говорят про *Родителя* или *Суперкласс*\n", + "(parent class, base class) и _Потомка_ или _Подкласс_ (child class, derived class)\n", + "\n", + "*Наследование позволяет быстро и без изменения родительского класса дополнять его функционал.*\n", + "\n", + "### Создание родительского класса и класса-потомка\n", + "Создадим класс Animal, который будет включать в себя наиболее общие свойства\n", + "и поведение животных: вес и длину (атрибуты), а также способность питаться и спать (методы)." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "565a534a", + "metadata": {}, + "outputs": [], + "source": [ + "# создадим класс Animal\n", + "class Animal:\n", + " \"\"\"класс Animal.\"\"\"\n", + "\n", + " # пропишем метод .__init__() с двумя параметрами: вес (кг) и длина (см)\n", + "\n", + " def __init__(self, weight, length):\n", + " \"\"\"Инициализация.\"\"\"\n", + " # поместим аргументы этих параметров в соответствующие переменные\n", + " self.weight = weight\n", + " self.length = length\n", + "\n", + " # объявим методы .eat()\n", + " def eat(self):\n", + " \"\"\"Метод кушоть.\"\"\"\n", + " print(\"Eating\")\n", + "\n", + " # и .sleep()\n", + " def sleep(self):\n", + " \"\"\"Метод спать.\"\"\"\n", + " print(\"Sleeping\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d173ad0f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.3 30\n", + "\n", + "Eating\n", + "Flying\n" + ] + } + ], + "source": [ + "# Теперь создадим класс-потомок Bird (птица).\n", + "# В него мы добавим возможность летать (метод).\n", + "\n", + "\n", + "# создадим класс Bird\n", + "# родительский класс Animal пропишем в скобках\n", + "class Birdv1(Animal):\n", + " \"\"\"класс класс-потомок Bird.\"\"\"\n", + "\n", + " # внутри класса Bird объявим новый метод .move()\n", + "\n", + " def move(self):\n", + " \"\"\"возможность летать (метод).\"\"\"\n", + " # для птиц .move() будет означать \"летать\"\n", + " print(\"Flying\")\n", + "\n", + "\n", + "# создадим объект pigeon и передадим ему значения веса и длины\n", + "pigeon = Birdv1(0.3, 30)\n", + "# посмотрим на унаследованные у класса Animal атрибуты\n", + "print(pigeon.weight, pigeon.length)\n", + "print()\n", + "# и методы\n", + "pigeon.eat()\n", + "\n", + "# Кроме того, мы можем вызвать метод, свойственный только классу Bird.\n", + "\n", + "pigeon.move()" + ] + }, + { + "cell_type": "markdown", + "id": "3ec9ad20", + "metadata": {}, + "source": [ + "### Функция super()\n", + "Eсли мы хотим добавить атрибут в классе-потомке, сохранив атрибуты\n", + "родительского класса, нам нужно явным образом вызвать последние с помощью функции super()." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6eeb59eb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.3 30 100\n", + "Sleeping\n", + "Flying\n" + ] + } + ], + "source": [ + "# снова создадим класс Bird\n", + "\n", + "\n", + "class Birdv2(Animal):\n", + " \"\"\"класс класс-потомок Bird.\"\"\"\n", + "\n", + " # в метод .__init__() добавим параметр скорости полета (км/ч)\n", + "\n", + " def __init__(self, weight, length, flying_speed):\n", + " \"\"\"Инициализация объекта.\"\"\"\n", + " # с помощью функции super() вызовем метод .__init__() родительского класса Animal\n", + " super().__init__(weight, length)\n", + " self.flying_speed = flying_speed\n", + "\n", + " # вновь пропишем метод .move()\n", + " def move(self):\n", + " \"\"\"метод движ.\"\"\"\n", + " print(\"Flying\")\n", + "\n", + "\n", + "# Без функции super() класс Bird не знал бы откуда брать параметры weight и length.\n", + "\n", + "# вновь создадим объект pigeon класса Bird, но уже с тремя параметрами\n", + "pigeon = Birdv2(0.3, 30, 100)\n", + "# вызовем как унаследованные, так и собственные атрибуты класса Bird\n", + "print(pigeon.weight, pigeon.length, pigeon.flying_speed)\n", + "# вызовем унаследованный метод .sleep()\n", + "pigeon.sleep()\n", + "# и собственный метод .move()\n", + "pigeon.move()" + ] + }, + { + "cell_type": "markdown", + "id": "5da9ef78", + "metadata": {}, + "source": [ + "### Переопределение класса\n", + "\n", + "Интересной особенностью класса-потомка в Питоне является то, что он\n", + "переопределяет (по сути, переписывает) родительский класс.\n", + "Давайте создадим подкласс для нелетающих птиц Flightless, в котором:\n", + "\n", + "- единственным атрибутом будет их скорость бега running_speed; а\n", + "- результат метода .move() мы заменим (что логично) с Flying на Running." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b9c5d6f0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "60\n", + "Running\n", + "Eating\n" + ] + } + ], + "source": [ + "# создадим подкласс Flightless класса Bird\n", + "class Flightless(Birdv2):\n", + " \"\"\"подкласс Flightless класса Bird.\"\"\"\n", + "\n", + " # метод .__init__() этого подкласса \"стирает\" .__init__() родительского класса\n", + "\n", + " def __init__(self, running_speed):\n", + " \"\"\"Инициализация объекта.\"\"\"\n", + " # таким образом, у нас остается только один атрибут\n", + " super().__init__(0, 0, 0)\n", + " self.running_speed = running_speed\n", + "\n", + " # кроме того, результатом метода .move() будет 'Running'\n", + " def move(self):\n", + " \"\"\"метод движение.\"\"\"\n", + " print(\"Running\")\n", + "\n", + "\n", + "# Создадим объект ostrich (страус) класса Flightless.\n", + "\n", + "\n", + "ostrich = Flightless(60)\n", + "# Посмотрим на значение атрибута скорости.\n", + "\n", + "# страусы бегают довольно быстро\n", + "print(ostrich.running_speed)\n", + "# Теперь посмотрим, переопределился ли метод .move().\n", + "\n", + "ostrich.move()\n", + "# Важно отметить, что в отличие от атрибутов, которые\n", + "# не наследуются автоматически (как мы видели, для\n", + "# этого нужно использовать функцию super()), методы\n", + "# всех родительских классов (в данном случае Animal —> Bird)\n", + "# передаются потомкам.\n", + "\n", + "# применим метод .eat() класса Animal\n", + "ostrich.eat()" + ] + }, + { + "cell_type": "markdown", + "id": "00fc0df4", + "metadata": {}, + "source": [ + "### Множественное наследование\n", + "Питон позволяет классу наследовать методы двух и более классов.\n", + "\n", + "Предположим, что мы хотим создать класс SwimmingBird (водоплавающая птица)\n", + "и взять методы плавания и полета у двух разных родительских классов, а именно Fish и Bird.\n", + "\n", + "Вначале создадим родительские классы и необходимые нам методы." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "89a5d249", + "metadata": {}, + "outputs": [], + "source": [ + "# создадим родительский класс Fish\n", + "class Fish:\n", + " \"\"\"родительский класс Fish.\"\"\"\n", + "\n", + " # и метод .swim()\n", + "\n", + " def __init__(self, running_speed):\n", + " \"\"\"Инициализация объекта.\"\"\"\n", + " self.type_ = \"fish\"\n", + " self.speed_ = running_speed\n", + "\n", + " def swim(self):\n", + " \"\"\"метод плавать.\"\"\"\n", + " print(\"Swimming\")\n", + "\n", + "\n", + "# и еще один родительский класс Bird\n", + "\n", + "\n", + "class Bird:\n", + " \"\"\"родительский класс Bird.\"\"\"\n", + "\n", + " def __init__(self, running_speed):\n", + " \"\"\"Инициализация объекта.\"\"\"\n", + " self.type_ = \"bird\"\n", + " self.speed_ = running_speed\n", + "\n", + " # и метод .fly()\n", + " def fly(self):\n", + " \"\"\"метод летать.\"\"\"\n", + " print(\"Flying\")\n", + "\n", + "\n", + "# Теперь перейдем к классу-потомку.\n", + "\n", + "# родительские классы мы перечисляем в скобках через зяпятую\n", + "# class SwimmingBird(Bird, Fish):\n", + "# pass\n", + "# # Создадим объект duck (утка) класса SwimmingBird.\n", + "#\n", + "# duck = SwimmingBird()\n", + "# # Как мы видим, утка умеет как летать, так и плавать.\n", + "#\n", + "# duck.fly()\n", + "# Flying\n", + "# duck.swim()\n", + "# Swimming" + ] + }, + { + "cell_type": "markdown", + "id": "9c338594", + "metadata": {}, + "source": [ + "## Полиморфизм\n", + "Полиморфизм (polymorphism) означает, что один и тот же объект\n", + "может принимать разные формы. В программировании, полиморфизм предполагает,\n", + "что операторы, функции и объекты могут взаимодействовать с различными типами данных.\n", + "\n", + "Например, оператор + в случае чисел предполагает сложение, а в случае строк — их объединение.\n", + "\n", + "### Полиморфизм функций\n", + "Полиморфные функции (polymorphic functions) — это функции, которые могут\n", + "работать с разными типами данных. Классическим примером является встроенная функция len().\n", + "\n", + "Ее можно применить к строке, списку, словарю или, например, массиву Numpy.\n", + "\n", + "Полиморфизм классов\n", + "Полиморфизм классов (class polymorphism) предполагает, что у разных\n", + "(не связанных друг с другом) классов могут быть методы с одинаковыми названиями." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "600171f7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Меня зовут Бегемот, я кот, цвет моей шерсти черный\n", + "Я умею мяукать\n", + "\n", + "Меня зовут Барбос, я пес, цвет моей шерсти серый\n", + "Я умею лаять\n", + "\n" + ] + } + ], + "source": [ + "# создадим класс котов\n", + "class CatClassv111:\n", + " \"\"\"класс котов.\"\"\"\n", + "\n", + " # определим атрибуты клички, типа и цвета шерсти\n", + "\n", + " def __init__(self, name, color):\n", + " \"\"\"атрибуты клички, типа и цвета шерсти.\"\"\"\n", + " self.name = name\n", + " self._type_ = \"кот\"\n", + " self.color = color\n", + "\n", + " # создадим метод .info() для вывода этих атрибутов\n", + " def info(self):\n", + " \"\"\"метод информация.\"\"\"\n", + " print(f\"Меня зовут {self.name}, я {self._type_}, цвет моей шерсти {self.color}\")\n", + "\n", + " # и метод .sound(), показывающий, что коты умеют мяукать\n", + " def sound(self):\n", + " \"\"\"метод звук.\"\"\"\n", + " print(\"Я умею мяукать\")\n", + "\n", + "\n", + "# создадим класс собак\n", + "\n", + "\n", + "class DogClassv111:\n", + " \"\"\"класс собак.\"\"\"\n", + "\n", + " # с такими же атрибутами\n", + "\n", + " def __init__(self, name, color):\n", + " \"\"\"атрибуты клички, типа и цвета шерсти.\"\"\"\n", + " self.name = name\n", + " self._type_ = \"пес\"\n", + " self.color = color\n", + "\n", + " # и методами\n", + " def info(self):\n", + " \"\"\"метод информация.\"\"\"\n", + " print(f\"Меня зовут {self.name}, я {self._type_}, цвет моей шерсти {self.color}\")\n", + "\n", + " # хотя, обратите внимание, действия внутри методов отличаются\n", + " def sound(self):\n", + " \"\"\"метод звук.\"\"\"\n", + " print(\"Я умею лаять\")\n", + "\n", + "\n", + "# Создадим объекты этих классов.\n", + "\n", + "\n", + "cat = CatClassv111(\"Бегемот\", \"черный\")\n", + "dog = DogClassv111(\"Барбос\", \"серый\")\n", + "# Поместим объекты в кортеж и в цикле for вызовем атрибуты и методы каждого из классов.\n", + "\n", + "for animal in (cat, dog):\n", + " animal.info()\n", + " animal.sound()\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "id": "5b93a3e5", + "metadata": {}, + "source": [ + "## Парадигма программирования\n", + "Парадигма программирования — это, по большому счету, способ организации\n", + "и стиль написания кода. Создание различных парадигм необходимо для того,\n", + "чтобы справиться со все возрастающей сложностью компьютерных программ.\n", + "\n", + "Как вы видите на схеме выше, парадигмы программирования можно разделить\n", + "на две большие группы: *императивное* и *декларативное* программирование\n", + "\n", + "### Императивное и декларативное программирование\n", + "*Императивное* программирование (imperative programming), как и предполагает его\n", + "название (от латинского imperare, «властвовать», «повелевать»), явным образом\n", + "говорит компьютеру, что нужно сделать. Другими словами, мы пишем инструкцию,\n", + "и компьютер строчка за строчкой ее исполняет.\n", + "\n", + "*Декларативный* подход (declarative programming) отличается тем, что детали\n", + "выполнения программы нас не интересуют, для нас важно лишь объяснить компьютеру,\n", + "какой результат мы хотим получить.\n", + "\n", + "Языки программирования, соответственно, можно разделить на императивные\n", + "(например, C или Питон) и декларативные (SQL, Haskell). Впрочем, такое\n", + "деление во многом условно, и чуть дальше я покажу вам, что мы, например,\n", + "уже использовали декларативную парадигму внутри Питона." + ] + }, + { + "cell_type": "markdown", + "id": "4acc8660", + "metadata": {}, + "source": [ + "### Процедурное программирование\n", + "Внутри *императивного* программирования выделяют процедурное программирование\n", + "(procedural programming). По большом счету, это обычное программирование,\n", + "которым мы занимались до сегодняшнего занятия. Ставим задачу и последовательно\n", + "через набор инструкций приходим к нужному решению.\n", + "\n", + "Впрочем, когда кода и людей его разрабатывающих становится слишком много,\n", + "мы довольно быстро сталкиваемся с недостатками такого подхода. Структура\n", + "кода становится не очевидной, найти ошибку бывает все сложнее и сложнее.\n", + "\n", + "### Объектно-ориентированное программирование\n", + "В мире ООП все задачи решаются не одной большой программой, а классами\n", + "(и созданными на их основе объектами). Под каждую задачу создается, как правило,\n", + "отдельный класс. И хотя поначалу использование классов может показаться довольно\n", + "сложным, на самом деле это существенно упрощает решение многих задач.\n", + "\n", + "Более того, изученные выше принципы объектно-ориентированного подхода,\n", + "а именно инкапсуляция, наследование и полиморфизм еще больше способствуют\n", + "грамотной организации кода.\n", + "\n", + "### Функциональное программирование\n", + "По большому счету, функциональное программирование (functional programming) —\n", + "это набор функций, которые последовательно решают поставленную задачу.\n", + "Результат работы одной функции становится входящим параметром для другой.\n", + "\n", + "*Решение через функциональный подход*\n", + "В частности, решим поставленную выше задачу, вначале последовательно применив\n", + "несколько функций (lambda-функцию, функцию map() и функцию list()) к словарю с\n", + "данными о пациентах." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3598a721", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[178, 182, 190]\n" + ] + }, + { + "data": { + "text/plain": [ + "183.33333333333334" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "patients = [\n", + " {\"name\": \"Николай\", \"height\": 178},\n", + " {\"name\": \"Иван\", \"height\": 182},\n", + " {\"name\": \"Алексей\", \"height\": 190},\n", + "]\n", + "# lambda-функция достанет значение по ключу height\n", + "# функция map() применит lambda-функцию к каждому вложенному в patients словарю\n", + "# функция list() преобразует результат в список\n", + "\n", + "heights = list(map(lambda x: x[\"height\"], patients))\n", + "print(heights)\n", + "\n", + "# После получения значений роста остается применить функции\n", + "# sum() и len() для расчета среднего значения.\n", + "\n", + "print(sum(heights) / len(heights))" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "acaf41e3", + "metadata": {}, + "outputs": [], + "source": [ + "# Функция einsum()\n", + "# Еще одним примером функционального программирования\n", + "# является функция einsum(). В данном случае мы берем\n", + "# два массива и описываем по каким правилам хотим их преобразовать.\n", + "\n", + "# # возьмем два двумерных массива\n", + "# a = np.array([[0, 1, 2],\n", + "# [3, 4, 5]])\n", + "#\n", + "# b = np.array([[5, 4],\n", + "# [3, 2],\n", + "# [1, 0]])\n", + "# # перемножим a и b по индексу j через функцию np.einsum()\n", + "# np.einsum('ij, jk -> ik', a, b)\n", + "# array([[ 5, 2],\n", + "# [32, 20]])" + ] + }, + { + "cell_type": "markdown", + "id": "81d834e1", + "metadata": {}, + "source": [ + "### Функциональное программирование на R\n", + "R — это декларативный функциональный язык, специально созданный для обработки\n", + "данных и статистических исследований. Если Питон в основном применяется для\n", + "решения задач бизнеса, то R чаще используется в науке.\n", + "\n", + "На языке R большая часть задач решается с помощью функций, которые последовательно\n", + "преобразуют передаваемые им данные. Рассмотрим вот такой пример подсчета количества\n", + "мальчиков по имени Тейлор в датасете babynames.\n", + "\n", + "*sum(select(filter(babynames, sex == \"M\", name == \"Taylor\"), n))*\n", + "\n", + "Даже если вы первый раз видите код на R довольно несложно догадаться, что в\n", + "данном случае мы (1) с помощью функции filter() находим мальчиков по имени\n", + "Тейлор в датасете babynames, затем (2) отбираем только эти строки через\n", + "select() и (3) наконец складываем результат.\n", + "\n", + "Ту же самую задачу можно реализовать через еще более «функциональный» код с\n", + "использованием оператора %>% (pipeline operator).\n", + "\n", + "# в таком виде последовательность становится еще более наглядной\n", + "babynames %>% filter(sex == \"M\", name == \"Taylor\") %>%\n", + " select(n) %>%\n", + " sum\n", + "\n", + "По сути мы создали пайплайн (то есть последовательность операций), где\n", + "каждый шаг решается определенной функцией." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/makarov/chapter_7_oop.py b/python/makarov/chapter_7_oop.py new file mode 100644 index 00000000..95bfefad --- /dev/null +++ b/python/makarov/chapter_7_oop.py @@ -0,0 +1,625 @@ +"""Глава 7. + +ООП. Классы и объекты. +""" + +# ## Понятие объектно-ориентированного программирования +# Отвлечемся на секунду от программирования. Представьте себе, что вам +# нужно нарисовать множество фигурок кошек. Хотя все кошки разные, у них все +# же есть нечто общее: +# +# - во-первых, у них есть общие свойства, например, шерсть, когти и хвост; +# - кроме того, любая кошка может выполнять определенные действия: лазить по +# деревьям, мяукать и потягиваться. +# +# Так вот объектно-ориентированное программирование предполагает, что вначале +# мы +# создаем шаблон нужного нам предмета (назовем его классом, class), а затем на +# основе шаблона создаем конкретный предмет (назовем его объектом, object). +# +# ## Классы и объекты в Питоне +# ### Создание класса и метод .__init__() + + +# создадим класс CatClass +class CatClassv1: + """Класс для представления кошки.""" + + # и пропишем метод .__init__() + def __init__(self): + """Инициализация объекта класса.""" + + +# ### Создание объекта + +# + +# создадим объект Matroskin класса CatClass +matroskin = CatClassv1() + +# проверим тип данных созданной переменной +type(matroskin) + + +# - + +# ### Атрибуты класса + + +# + +# вновь создадим класс CatClass +class CatClassv2: + """Класс для представления кошки.""" + + # метод .__init__() на этот раз принимает еще и параметр color + + def __init__(self, color): + """Инициализация объекта класса.""" + # этот параметр будет записан в переменную атрибута с таким же + # названием + self.color = color + + # значение атрибута type_ задается внутри класса + self.type_ = "cat" + + +# повторно создадим объект класса CatClass, передав ему параметр цвета шерсти +# matroskin = CatClassv2("gray") + +# и выведем атрибуты класса +# matroskin.color, matroskin.type_ + + +# - + +# ### Методы класса + + +# перепишем класс CatClass +class CatClassv11: + """Класс для представления кошки.""" + + # метод .__init__() и атрибуты оставим без изменений + + def __init__(self, color): + """Инициализация объекта класса.""" + self.color = color + self.type_ = "cat" + + # однако добавим метод, который позволит коту мяукать + def meow(self): + """Метод класса, голос объекта.""" + for i in range(3): + print("Мяу", i) + + # и метод .info() для вывода информации об объекте + def info(self): + """Метод класса, информация об объекте.""" + print(self.color, self.type_) + + +# создадим объект +# matroskin = CatClassv11("gray") +print() +# применим метод .meow() +# matroskin.meow() +print() +# и метод .info() +# matroskin.info() + +# ## Принципы объектно-ориентированного программирования +# ### Инкапсуляция +# Инкапсуляция (encapsulation) — это способность класса хранить данные +# и методы внутри себя. Другими словами, объект класса можно представить +# в виде капсулы, в которой содержатся необходимые данные и методы. +# +# ## Публичные и частные атрибуты класса +# С понятием инкапсуляции тесно связаны понятия публичных и частных +# атрибутов (public and private attributes). Публичные атрибуты — это те +# атрибуты, к которым можно получить доступ за пределами «капсулы» класса. +# +# *По умолчанию все атрибуты в Питоне публичные.* +# +# + +# + +# изменим атрибут type_ объекта Matroskin на dog +# matroskin.type_ = "dog" + +# выведем этот атрибут +# matroskin.type_ + +# Согласитесь, это не очень разумно. Нам бы хотелось, +# чтобы объекты класса CatClass не изменяли значения +# атрибута type_. Другими словами, нам нужно сделать +# этот атрибут частным. Здесь есть два способа: + + +# + +# Способ 1. +class CatClassv12: + """Поставить один символ подчеркивания перед атрибутом.""" + + def __init__(self, color): + """Инициализация.""" + self.color = color + # символ подчеркивания ПЕРЕД названием атрибута указывает, + # что это частный атрибут и изменять его не стоит + self._type_ = "cat" + + +# это лишь частично решает проблему + + +# вновь создадим объект класса CatClass +# Matroskin = CatClass("gray") +# +# # и изменим значение атрибута _type_ +# Matroskin._type_ = "dog" +# Matroskin._type_ + + +# + +# Способ 2. +class CatClassv13: + """Поставить перед названием атрибута __.""" + + def __init__(self, color): + """Инициализация.""" + self.color = color + # символ двойного подчеркивания предотвратит доступ извне + # self.__type_ = "cat" + + +# Matroskin = CatClass('gray') +# +# # теперь при вызове этого атрибута Питон выдаст ошибку +# Matroskin. +# выведет ошибку + +# К сожалению, и это ограничение можно обойти, поставив +# _НазваниеКласса перед атрибутом. + +# поставим _CatClass перед __type_, +# изменим значение атрибута и +# Matroskin._CatClass__type_ = 'dog' +# +# # выведем его +# Matroskin._CatClass__type_ +# - + +# ### Наследование +# Принцип *наследования* (inheritance) предполагает, что один класс наследует +# атрибуты и методы другого. В этом случае, говорят про *Родителя* или +# *Суперкласс* +# (parent class, base class) и _Потомка_ или _Подкласс_ (child class, derived +# class) +# +# *Наследование позволяет быстро и без изменения родительского класса +# дополнять его функционал.* +# +# ### Создание родительского класса и класса-потомка +# Создадим класс Animal, который будет включать в себя наиболее общие свойства +# и поведение животных: вес и длину (атрибуты), а также способность питаться и +# спать (методы). + + +# создадим класс Animal +class Animal: + """Класс Animal.""" + + # пропишем метод .__init__() с двумя параметрами: вес (кг) и длина (см) + + def __init__(self, weight, length): + """Инициализация.""" + # поместим аргументы этих параметров в соответствующие переменные + self.weight = weight + self.length = length + + # объявим методы .eat() + def eat(self): + """Метод кушоть.""" + print("Eating") + + # и .sleep() + def sleep(self): + """Метод спать.""" + print("Sleeping") + + +# + +# Теперь создадим класс-потомок Bird (птица). +# В него мы добавим возможность летать (метод). + + +# создадим класс Bird +# родительский класс Animal пропишем в скобках +class Birdv1(Animal): + """Класс класс-потомок Bird.""" + + # внутри класса Bird объявим новый метод .move() + + def move(self): + """Возможность летать (метод).""" + # для птиц .move() будет означать "летать" + print("Flying") + + +# создадим объект pigeon и передадим ему значения веса и длины +pigeon = Birdv1(0.3, 30) +# посмотрим на унаследованные у класса Animal атрибуты +print(pigeon.weight, pigeon.length) +print() +# и методы +pigeon.eat() + +# Кроме того, мы можем вызвать метод, свойственный только классу Bird. + +pigeon.move() +# - + +# ### Функция super() +# Eсли мы хотим добавить атрибут в классе-потомке, сохранив атрибуты +# родительского класса, нам нужно явным образом вызвать последние с помощью +# функции super(). + +# + +# снова создадим класс Bird + + +class Birdv2(Animal): + """Класс класс-потомок Bird.""" + + # в метод .__init__() добавим параметр скорости полета (км/ч) + + def __init__(self, weight, length, flying_speed): + """Инициализация объекта.""" + # с помощью функции super() вызовем метод .__init__() родительского + # класса Animal + super().__init__(weight, length) + self.flying_speed = flying_speed + + # вновь пропишем метод .move() + def move(self): + """Метод движ.""" + print("Flying") + + +# Без функции super() класс Bird не знал бы откуда брать параметры weight и +# length. + +# вновь создадим объект pigeon класса Bird, но уже с тремя параметрами +# pigeon = Birdv2(0.3, 30, 100) +# вызовем как унаследованные, так и собственные атрибуты класса Bird +# print(pigeon.weight, pigeon.length, pigeon.flying_speed) +# вызовем унаследованный метод .sleep() +pigeon.sleep() +# и собственный метод .move() +pigeon.move() + + +# - + +# ### Переопределение класса +# +# Интересной особенностью класса-потомка в Питоне является то, что он +# переопределяет (по сути, переписывает) родительский класс. +# Давайте создадим подкласс для нелетающих птиц Flightless, в котором: +# +# - единственным атрибутом будет их скорость бега running_speed; а +# - результат метода .move() мы заменим (что логично) с Flying на Running. + + +# + +# создадим подкласс Flightless класса Bird +class Flightless(Birdv2): + """Подкласс Flightless класса Bird.""" + + # метод .__init__() этого подкласса "стирает" .__init__() родительского + # класса + + def __init__(self, running_speed): + """Инициализация объекта.""" + # таким образом, у нас остается только один атрибут + super().__init__(0, 0, 0) + self.running_speed = running_speed + + # кроме того, результатом метода .move() будет 'Running' + def move(self): + """Метод движение.""" + print("Running") + + +# Создадим объект ostrich (страус) класса Flightless. + + +ostrich = Flightless(60) +# Посмотрим на значение атрибута скорости. + +# страусы бегают довольно быстро +print(ostrich.running_speed) +# Теперь посмотрим, переопределился ли метод .move(). + +ostrich.move() +# Важно отметить, что в отличие от атрибутов, которые +# не наследуются автоматически (как мы видели, для +# этого нужно использовать функцию super()), методы +# всех родительских классов (в данном случае Animal —> Bird) +# передаются потомкам. + +# применим метод .eat() класса Animal +ostrich.eat() + + +# - + +# ### Множественное наследование +# Питон позволяет классу наследовать методы двух и более классов. +# +# Предположим, что мы хотим создать класс SwimmingBird (водоплавающая птица) +# и взять методы плавания и полета у двух разных родительских классов, а +# именно Fish и Bird. +# +# Вначале создадим родительские классы и необходимые нам методы. + + +# + +# создадим родительский класс Fish +class Fish: + """Родительский класс Fish.""" + + # и метод .swim() + + def __init__(self, running_speed): + """Инициализация объекта.""" + self.type_ = "fish" + self.speed_ = running_speed + + def swim(self): + """Метод плавать.""" + print("Swimming") + + +# и еще один родительский класс Bird + + +class Bird: + """Родительский класс Bird.""" + + def __init__(self, running_speed): + """Инициализация объекта.""" + self.type_ = "bird" + self.speed_ = running_speed + + # и метод .fly() + def fly(self): + """Метод летать.""" + print("Flying") + + +# Теперь перейдем к классу-потомку. + +# родительские классы мы перечисляем в скобках через зяпятую +# class SwimmingBird(Bird, Fish): +# pass +# # Создадим объект duck (утка) класса SwimmingBird. +# +# duck = SwimmingBird() +# # Как мы видим, утка умеет как летать, так и плавать. +# +# duck.fly() +# Flying +# duck.swim() +# Swimming +# - + +# ## Полиморфизм +# Полиморфизм (polymorphism) означает, что один и тот же объект +# может принимать разные формы. В программировании, полиморфизм предполагает, +# что операторы, функции и объекты могут взаимодействовать с различными типами +# данных. +# +# Например, оператор + в случае чисел предполагает сложение, а в случае строк +# — их объединение. +# +# ### Полиморфизм функций +# Полиморфные функции (polymorphic functions) — это функции, которые могут +# работать с разными типами данных. Классическим примером является встроенная +# функция len(). +# +# Ее можно применить к строке, списку, словарю или, например, массиву Numpy. +# +# Полиморфизм классов +# Полиморфизм классов (class polymorphism) предполагает, что у разных +# (не связанных друг с другом) классов могут быть методы с одинаковыми +# названиями. + + +# + +# создадим класс котов +class CatClassv111: + """Класс котов.""" + + # определим атрибуты клички, типа и цвета шерсти + + def __init__(self, name, color): + """Атрибуты клички, типа и цвета шерсти.""" + self.name = name + self._type_ = "кот" + self.color = color + + # создадим метод .info() для вывода этих атрибутов + def info(self): + """Метод информация.""" + # print(f"Меня зовут {self.name}, я {self._type_}, + # цвет моей шерсти {self.color}") + + # и метод .sound(), показывающий, что коты умеют мяукать + def sound(self): + """Метод звук.""" + print("Я умею мяукать") + + +# создадим класс собак + + +class DogClassv111: + """Класс собак.""" + + # с такими же атрибутами + + def __init__(self, name, color): + """Атрибуты клички, типа и цвета шерсти.""" + self.name = name + self._type_ = "пес" + self.color = color + + # и методами + def info(self): + """Метод информация.""" + # print(f"Меня зовут {self.name}, я {self._type_}, + # цвет моей шерсти {self.color}") + + # хотя, обратите внимание, действия внутри методов отличаются + def sound(self): + """Метод звук.""" + print("Я умею лаять") + + +# Создадим объекты этих классов. + + +cat = CatClassv111("Бегемот", "черный") +dog = DogClassv111("Барбос", "серый") +# Поместим объекты в кортеж и в цикле for вызовем атрибуты и методы каждого из +# классов. + +for animal in (cat, dog): + animal.info() + animal.sound() + print() +# - + +# ## Парадигма программирования +# Парадигма программирования — это, по большому счету, способ организации +# и стиль написания кода. Создание различных парадигм необходимо для того, +# чтобы справиться со все возрастающей сложностью компьютерных программ. +# +# Как вы видите на схеме выше, парадигмы программирования можно разделить +# на две большие группы: *императивное* и *декларативное* программирование +# +# ### Императивное и декларативное программирование +# *Императивное* программирование (imperative programming), как и предполагает +# его +# название (от латинского imperare, «властвовать», «повелевать»), явным образом +# говорит компьютеру, что нужно сделать. Другими словами, мы пишем инструкцию, +# и компьютер строчка за строчкой ее исполняет. +# +# *Декларативный* подход (declarative programming) отличается тем, что детали +# выполнения программы нас не интересуют, для нас важно лишь объяснить +# компьютеру, +# какой результат мы хотим получить. +# +# Языки программирования, соответственно, можно разделить на императивные +# (например, C или Питон) и декларативные (SQL, Haskell). Впрочем, такое +# деление во многом условно, и чуть дальше я покажу вам, что мы, например, +# уже использовали декларативную парадигму внутри Питона. + +# ### Процедурное программирование +# Внутри *императивного* программирования выделяют процедурное программирование +# (procedural programming). По большом счету, это обычное программирование, +# которым мы занимались до сегодняшнего занятия. Ставим задачу и +# последовательно +# через набор инструкций приходим к нужному решению. +# +# Впрочем, когда кода и людей его разрабатывающих становится слишком много, +# мы довольно быстро сталкиваемся с недостатками такого подхода. Структура +# кода становится не очевидной, найти ошибку бывает все сложнее и сложнее. +# +# ### Объектно-ориентированное программирование +# В мире ООП все задачи решаются не одной большой программой, а классами +# (и созданными на их основе объектами). Под каждую задачу создается, как +# правило, +# отдельный класс. И хотя поначалу использование классов может показаться +# довольно +# сложным, на самом деле это существенно упрощает решение многих задач. +# +# Более того, изученные выше принципы объектно-ориентированного подхода, +# а именно инкапсуляция, наследование и полиморфизм еще больше способствуют +# грамотной организации кода. +# +# ### Функциональное программирование +# По большому счету, функциональное программирование (functional programming) — +# это набор функций, которые последовательно решают поставленную задачу. +# Результат работы одной функции становится входящим параметром для другой. +# +# *Решение через функциональный подход* +# В частности, решим поставленную выше задачу, вначале последовательно применив +# несколько функций (lambda-функцию, функцию map() и функцию list()) к словарю +# с +# данными о пациентах. + +# + +patients = [ + {"name": "Николай", "height": 178}, + {"name": "Иван", "height": 182}, + {"name": "Алексей", "height": 190}, +] +# lambda-функция достанет значение по ключу height +# функция map() применит lambda-функцию к каждому вложенному в patients словарю +# функция list() преобразует результат в список + +heights = list(map(lambda x: x["height"], patients)) +print(heights) + +# После получения значений роста остается применить функции +# sum() и len() для расчета среднего значения. + +# print(sum(heights) / len(heights)) + +# + +# Функция einsum() +# Еще одним примером функционального программирования +# является функция einsum(). В данном случае мы берем +# два массива и описываем по каким правилам хотим их преобразовать. + +# # возьмем два двумерных массива +# a = np.array([[0, 1, 2], +# [3, 4, 5]]) +# +# b = np.array([[5, 4], +# [3, 2], +# [1, 0]]) +# # перемножим a и b по индексу j через функцию np.einsum() +# np.einsum('ij, jk -> ik', a, b) +# array([[ 5, 2], +# [32, 20]]) +# - + +# ### Функциональное программирование на R +# R — это декларативный функциональный язык, специально созданный для обработки +# данных и статистических исследований. Если Питон в основном применяется для +# решения задач бизнеса, то R чаще используется в науке. +# +# На языке R большая часть задач решается с помощью функций, которые +# последовательно +# преобразуют передаваемые им данные. Рассмотрим вот такой пример подсчета +# количества +# мальчиков по имени Тейлор в датасете babynames. +# +# *sum(select(filter(babynames, sex == "M", name == "Taylor"), n))* +# +# Даже если вы первый раз видите код на R довольно несложно догадаться, что в +# данном случае мы (1) с помощью функции filter() находим мальчиков по имени +# Тейлор в датасете babynames, затем (2) отбираем только эти строки через +# select() и (3) наконец складываем результат. +# +# Ту же самую задачу можно реализовать через еще более «функциональный» код с +# использованием оператора %>% (pipeline operator). +# +# # в таком виде последовательность становится еще более наглядной +# babynames %>% filter(sex == "M", name == "Taylor") %>% +# select(n) %>% +# sum +# +# По сути мы создали пайплайн (то есть последовательность операций), где +# каждый шаг решается определенной функцией. diff --git a/python/makarov/chapter_8_lists_tuples_sets.ipynb b/python/makarov/chapter_8_lists_tuples_sets.ipynb new file mode 100644 index 00000000..8e33372e --- /dev/null +++ b/python/makarov/chapter_8_lists_tuples_sets.ipynb @@ -0,0 +1,2544 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"Макаров.\n", + "\n", + "Списки, кортежи и множества.\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0AoPSXyUTTLc" + }, + "source": [ + "## Списки, кортежи и множества" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lIM5gFo4TbUg" + }, + "source": [ + "### Списки" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PPEbDV8hCAGO" + }, + "source": [ + "Основы работы со списками" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "x3wxNu5jthst", + "outputId": "9ea10800-7ade-4833-d849-424f4252cab8" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[] []\n" + ] + } + ], + "source": [ + "# пустой список можно создать через [] или функцию list()\n", + "# импортируем класс стеммера и создаем объект\n", + "from nltk.stem import PorterStemmer\n", + "\n", + "some_list_1: list[str] = []\n", + "some_list_2: list[str] = list() # pylint: disable=R1734\n", + "\n", + "print(some_list_1, some_list_2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tLWO1t--thwP", + "outputId": "bdba1e22-059a-4ae5-b5b7-f8cf32544eec" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[3, 'число три', ['число', 'три'], {'число': 3}]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# элементами списка могут, в частности, быть числа, строки,\n", + "# другие списки и словари\n", + "number_three: list[int | str | list[str] | dict[str, int]] = [\n", + " 3,\n", + " \"число три\",\n", + " [\"число\", \"три\"],\n", + " {\"число\": 3},\n", + "]\n", + "number_three" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "_jEdnwKSkbSE", + "outputId": "c50a7419-d925-4a2c-ec7d-f705e2c988c0" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "4" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# длина списка рассчитывается через функцию len()\n", + "len(number_three)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9KkaG7NJDOMW" + }, + "source": [ + "Индекс и срез списка" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "b3GS578dDRSH", + "outputId": "76a19d40-7499-4467-efd0-8d07b1b5d968" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a e\n" + ] + } + ], + "source": [ + "# у списка есть положительный и отрицательный индексы\n", + "abc_list: list[str] = [\"a\", \"b\", \"c\", \"d\", \"e\"]\n", + "\n", + "# воспользуемся ими для вывода первого и последнего элементов\n", + "print(abc_list[0], abc_list[-1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "LsfIU3Z3F6Qo", + "outputId": "ad2627b5-bc55-438f-ab49-be1c0ed9814e" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Игорь'" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# при работе с вложенным списком\n", + "salary_list: list[list[str | int]] = [\n", + " [\"Анна\", 90000],\n", + " [\"Игорь\", 85000],\n", + " [\"Алексей\", 95000],\n", + "]\n", + "\n", + "# мы вначале указываем индекс вложенного списка, а затем индекс элемента в нем\n", + "salary_list[1][0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hzcsnn7LISyc", + "outputId": "8e597d24-f23d-41a7-d055-70220a1f033f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "2" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# индекс можно узнать с помощью метода .index()\n", + "abc_list.index(\"c\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ARwsxkVfrFOQ", + "outputId": "3137c4c5-16bd-4ccb-e448-81cb54de5270" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# метод .index() можно применить и ко вложенному списку\n", + "salary_list[0].index(90000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VvcCb_ZaItpp", + "outputId": "25c98c5c-e90b-4adc-b28d-94d4802ed786" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Вт', 'Ср', 'Чт', 'Пт']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим список с днями недели\n", + "days_list: list[str] = [\"Пн\", \"Вт\", \"Ср\", \"Чт\", \"Пт\", \"Сб\", \"Вс\"]\n", + "\n", + "# и выведем со второго по пятый элемент включительно\n", + "days_list[1:5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vFJFJGigJ-kQ", + "outputId": "a0b65aff-7ef8-428c-ea4f-9bd14651f442" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Пн', 'Ср', 'Пт']" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# выведем каждый второй элемент в срезе с первого по пятый\n", + "days_list[:5:2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "n6Q6not7t9GH", + "outputId": "57d9edce-4af6-4e33-b058-147d844289e7" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# проверим есть ли \"Пн\" в списке\n", + "\"Пн\" in days_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HpVMXHWDuXy7", + "outputId": "5fd5743a-2da3-41a3-f875-ae4276e1cd63" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Такое слово есть\n" + ] + } + ], + "source": [ + "# если \"Вт\" есть в списке\n", + "if \"Вт\" in days_list:\n", + "\n", + " # выведем сообщение\n", + " print(\"Такое слово есть\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "msuaGJ1OLXrB" + }, + "source": [ + "Добавление, замена и удаление элементов списка" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fEyyqpUDLcsY" + }, + "outputs": [], + "source": [ + "# создадим список\n", + "weekdays: list[str] = [\"Понедельник\", \"Вторник\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2YK5UIHOnZwq", + "outputId": "5fa9a3c3-f203-458c-a4fa-befa0b0f36a9" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Вторник', 'Четверг']" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавим один элемент в конец списка с помощью метода .append()\n", + "weekdays.append(\"Четверг\")\n", + "weekdays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Yvrd-wOMnZ9d", + "outputId": "8e85dec1-5b22-47c3-be53-25b8c2f3aa42" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Вторник', 'Среда', 'Четверг']" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавим элемент в определенное место в списке\n", + "# через желаемый индекс этого элемента\n", + "weekdays.insert(2, \"Среда\")\n", + "weekdays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "zPEqoCsrzKEB", + "outputId": "c7214ad0-de20-4d05-e178-0ae0b29081fe" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Вторник', 'Среда', 'Пятница']" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# изменим четвертый элемент в списке\n", + "weekdays[3] = \"Пятница\"\n", + "weekdays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "gsWduacznqg4", + "outputId": "0ffc359c-e8dc-473a-d2dd-6bb573746afc" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Вторник', 'Среда']" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# удалим элемент по его значению\n", + "weekdays.remove(\"Пятница\")\n", + "weekdays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "D2bnKXNAxmq2", + "outputId": "94426985-ebca-423b-e80a-dc3f5bc0a8b1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Вторник']" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# удалим элемент по его индексу через ключевое слово del\n", + "del weekdays[2]\n", + "weekdays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "CooE-D9ouFeP", + "outputId": "149a53e2-baf6-4e8e-85a4-630ce28819a5" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Вторник'" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# сделаем то же самое с помощью метода .pop()\n", + "# этот метод выводит удаляемый элемент\n", + "weekdays.pop(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "kM8rmPNXuyN6", + "outputId": "f1a810fc-ccb3-4ccf-8f25-480dbb83f25a" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник']" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# посмотрим, что осталось в нашем списке\n", + "weekdays" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MWP0v0fz0IQ4" + }, + "source": [ + "Сложение списков" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cwu9M49e0HlB", + "outputId": "66ef1e04-7468-47c7-9997-fd250cedf9f3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница']" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# соединить два списка можно с помощью метода .extend()\n", + "more_weekdays: list[str] = [\"Вторник\", \"Среда\", \"Четверг\", \"Пятница\"]\n", + "\n", + "weekdays.extend(more_weekdays)\n", + "weekdays" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "CE07IDeZx0cl", + "outputId": "e4674475-aa75-4468-a95b-f5a0c142300f" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье']\n" + ] + } + ], + "source": [ + "weekend: list[str] = [\"Суббота\", \"Воскресенье\"]\n", + "\n", + "# или просто сложив два списка\n", + "print(weekdays + weekend)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pJcSZ0jiz840", + "outputId": "7edd4ed0-2c01-4beb-ca00-f2e135746e97" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Понедельник']" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# иногда бывает полезно \"размножить\" элементы списка\n", + "print([\"Понедельник\"] * 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3MRsPPs30N1V", + "outputId": "5d0b022c-1487-43dc-b8dd-c4a5751187e0" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Понедельник', 'Понедельник', 'Вторник', 'Вторник']" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# такие \"произведения\" также можно складывать\n", + "print([\"Понедельник\"] * 2 + [\"Вторник\"] * 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5zWQeyD4lsk9" + }, + "source": [ + "Распаковка списков" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "n6kQjWdPlv7P" + }, + "outputs": [], + "source": [ + "# дан список\n", + "# \"_\" добавлен для того, чтобы избежать дублирования кода\n", + "# и как следствие ошибок pylint\n", + "week: list[str] = [\n", + " \"Понедельник_\",\n", + " \"Вторник_\",\n", + " \"Среда_\",\n", + " \"Четверг_\",\n", + " \"Пятница_\",\n", + " \"Суббота_\",\n", + " \"Воскресенье_\",\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "ZquIS9Lhl2z_", + "outputId": "4c532ff3-8e31-45e0-ac63-515e8b9b621d" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Понедельник'" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# указав индекс элемента, его можно записать в переменную\n", + "monday = week[0]\n", + "monday" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "1HAhG91Dl22z", + "outputId": "d0fd205e-f2c4-4888-fb93-7d0fa82464ba" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('Понедельник', 'Вторник', 'Среда')" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# срез можно поместить в несколько переменных\n", + "monday, tuesday, wednesday = week[:3]\n", + "\n", + "# важно, чтобы количество элементов среза было равно количеству переменных\n", + "monday, tuesday, wednesday" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "hfnnO_eUl25o", + "outputId": "cbf4587c-f1f0-445b-b973-64dd677f43f6" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Понедельник'" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# можно выделить первый элемент, а остальные поместить\n", + "# в переменную со звездочкой\n", + "monday, *rest = week\n", + "monday" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7oVKz24-m9lY", + "outputId": "de4351b4-5e71-49b6-cb0b-beedca62c8c8" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('Понедельник', 'Воскресенье')" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# также можно поступить, например, с первым и последним элементом\n", + "monday, *days, sunday = week\n", + "monday, sunday" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xgSI_44Mqlwv", + "outputId": "53e11e9b-8830-48e0-97c5-986219ff5dc0" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота']" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# посмотрим, какие элементы остались в переменной со звездочкой\n", + "days" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "CZZ2Tq0yq4l5" + }, + "source": [ + "Сортировка списков" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zTBWIYWZr80H" + }, + "outputs": [], + "source": [ + "# возьмем список чисел\n", + "nums: list[int] = [25, 10, 30, 20, 5, 15]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Zt9iwWx3q7IL", + "outputId": "b991cb38-26b3-4c26-a6d9-668056437217" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[5, 10, 15, 20, 25, 30]" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# и отсортируем с помощью функции sorted(), результат выводится сразу\n", + "sorted(nums)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vS7G44sVs0jv", + "outputId": "14debf29-01e2-48ba-9d67-120ac5d35748" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[25, 10, 30, 20, 5, 15]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# исходный список при этом не изменился\n", + "nums" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Qbi91ZlWv116", + "outputId": "09bd4d25-2a75-4517-a261-df619a283929" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[5, 10, 15, 20, 25, 30]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если поместить результат в переменную, изменения сохранятся\n", + "sorted_nums = sorted(nums)\n", + "sorted_nums" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "J92cKG_ZsGJd" + }, + "outputs": [], + "source": [ + "# метод .sort() сохраняет результат, но не выводит его сразу\n", + "# reverse = True задает сортировку по убыванию\n", + "nums.sort(reverse=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tMLloVoxsdcW", + "outputId": "fa528c25-7eea-4131-dc2a-5ac2758bcc1f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[30, 25, 20, 15, 10, 5]" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# выведем результат\n", + "nums" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "kU0tmatFulXn", + "outputId": "0ea3f3cf-fdd9-48dd-b7c5-b3aea0221c28" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[5, 10, 15, 20, 25, 30]" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# метод .reverse() задает обратный порядок, сохраняет, но не выводит результат\n", + "nums.reverse()\n", + "\n", + "# его также нужно вывести отдельно\n", + "nums" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "BZfKDeRM3fbf", + "outputId": "163b97aa-7255-4e8d-fa57-4e932be32b20" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# функция reversed() возвращает итератор\n", + "reversed(nums)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7piJhHSn8aUW", + "outputId": "e2da4c5b-f524-4926-ed00-b59dab91cab3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[30, 25, 20, 15, 10, 5]" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вывести результат можно с помощью функции list()\n", + "list(reversed(nums))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ldVNvlbg8v3_", + "outputId": "bd43b64e-2679-4060-bd33-cc634c6189f1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[5, 10, 15, 20, 25, 30]" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# результат при этом не сохраняется\n", + "nums" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_Xyi6IdeuA-4" + }, + "source": [ + "Преобразование списка в строку" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "iUoGSZMq0JFD" + }, + "outputs": [], + "source": [ + "# дан список из строковых элементов\n", + "str_list: list[str] = [\"P\", \"y\", \"t\", \"h\", \"o\", \"n\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "KuKfbsZLuER1", + "outputId": "70e66ff3-2188-42dc-e5cb-5a2f3d446c98" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Python'" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# с помощью метода .join() можно соединить все элементы\n", + "joined_str = \"\".join(str_list)\n", + "joined_str" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "WfMTmZcEzgky", + "outputId": "5e00ef97-a330-431f-c3c2-770330aaeaf3" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'P_y_t_h_o_n'" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если в кавычках ничего не указывать, элементы просто соединятся,\n", + "# но можно указать любой другой элемент\n", + "joined_str_ = \"_\".join(str_list)\n", + "joined_str_" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uEFM3lgzzr_k" + }, + "source": [ + "Арифметика в списках" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "tGBnQ-mFzwJw" + }, + "outputs": [], + "source": [ + "# дан список чисел\n", + "nums_: list[int] = [3, 2, 1, 4, 5, 12, 3, 3, 7, 9, 11, 15]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VjwNZw2JzwUG", + "outputId": "e8586a86-a592-444e-9e3c-23ef494a040d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# с помощью метода .count() мы можем посчитать частоту вхождения\n", + "# элемента в список\n", + "nums_.count(3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rrRSZEb13P0e", + "outputId": "d64be983-954e-44e2-cf3a-d801a61a848e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1 15 75\n" + ] + } + ], + "source": [ + "# кроме того мы можем найти минимальное и максимальное значения\n", + "# и сумму элементов\n", + "print(min(nums_), max(nums_), sum(nums_))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zZKefwcpZ_rd" + }, + "source": [ + "List comprehension" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "gKYUJua2aCdY" + }, + "outputs": [], + "source": [ + "# дан список имен\n", + "# оставим имена, начинающиеся с буквы \"А\"\n", + "names: list[str] = [\n", + " \"Артем\",\n", + " \"Антон\",\n", + " \"Александр\",\n", + " \"Борис\",\n", + " \"Виктор\",\n", + " \"Геннадий\",\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "iZhNYZ7raCw_", + "outputId": "c8806615-90af-4669-da6e-ff3083e1dcba" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Артем', 'Антон', 'Александр']" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вначале решим эту задачу с помощью цикла for\n", + "\n", + "# создадим пустой список\n", + "a_names: list[str] = []\n", + "\n", + "# пройдемся по исходному списку в цикле for\n", + "for name in names:\n", + "\n", + " # с помощью метода .startswith() проверим, начинается ли слово с \"А\"\n", + " if name.startswith(\"А\"):\n", + "\n", + " # если да, добавим в новый список\n", + " a_names.append(name)\n", + "\n", + "# выведем результат\n", + "a_names" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RfU5aFoia66k", + "outputId": "fb93053e-0d50-4df5-8941-2280ad774ed7" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Артем', 'Антон', 'Александр']" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# эту же задачу можно решить через list comprehension\n", + "# по сути мы пишем: \"что сделать, пока есть элемент в списке, при каком условии\"\n", + "a_names = [name for name in names if name.startswith(\"А\")]\n", + "a_names" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PtAJqkZRsQGM", + "outputId": "57ffe7da-07b4-4106-9226-e26ccf433fb0" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['артем', 'антон', 'александр', 'борис', 'виктор', 'геннадий']" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# переведем все буквы в строчные, условие здесь не нужно\n", + "lower_names = [name.lower() for name in names]\n", + "lower_names" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "aj8uLZu9clcD", + "outputId": "558587b2-02a1-4339-dc8b-18e38a05d74a" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['Артем', 'Антон', 'Александр', 'Борис', 'Вадим', 'Геннадий']" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# схема условия if-else немного отличается\n", + "# оставляем имя, если это не Виктор, если Виктор - заменяем на Вадим\n", + "replace_name = [name if name != \"Виктор\" else \"Вадим\" for name in names]\n", + "replace_name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "EiKriSA89dJk", + "outputId": "a6964157-1f0e-4cf7-f53f-0cadad414ce5" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['pari', 'visit', 'lot', 'museum', 'first', 'went', 'louvr', 'largest', 'art', 'museum', 'world', 'alway', 'interest', 'art', 'spent', 'mani', 'hour', 'museum', 'enourm', 'week', 'would', 'enough']\n" + ] + } + ], + "source": [ + "# на занятии по обработке естественного языка с помощью list comprehension\n", + "# мы применили стеммер Портера к списку слов\n", + "lemmatized: list[str] = [\n", + " \"paris\",\n", + " \"visited\",\n", + " \"lot\",\n", + " \"museum\",\n", + " \"first\",\n", + " \"went\",\n", + " \"louvre\",\n", + " \"largest\",\n", + " \"art\",\n", + " \"museum\",\n", + " \"world\",\n", + " \"always\",\n", + " \"interested\",\n", + " \"art\",\n", + " \"spent\",\n", + " \"many\",\n", + " \"hour\",\n", + " \"museum\",\n", + " \"enormous\",\n", + " \"week\",\n", + " \"would\",\n", + " \"enough\",\n", + "]\n", + "\n", + "\n", + "porter = PorterStemmer()\n", + "\n", + "# применяем стеммер к элементу s, пока есть элементы s в списке lemmatized\n", + "stemmed_p = [porter.stem(s) for s in lemmatized]\n", + "print(stemmed_p)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kY91ANMfXeRG" + }, + "source": [ + "### Кортежи" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aF48XEbsCsV4" + }, + "source": [ + "Основы работы с кортежами" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qVBaa3SrtlYB", + "outputId": "c561c5ad-c089-450a-9300-7b1d5e2858e5" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "() ()\n" + ] + } + ], + "source": [ + "# пустой кортеж можно создать с помощью пустых круглых скобок ()\n", + "# или функции tuple()\n", + "tuple_1: tuple[()] = ()\n", + "tuple_2: tuple[str, ...] = tuple()\n", + "print(tuple_1, tuple_2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "Vv-okCt8tlau", + "outputId": "09cb5284-ae26-4057-a206-7b414437d4f3" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'a'" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# в кортеже элементы упорядочены, а значит есть индекс\n", + "letters: tuple[str, ...] = (\"a\", \"b\", \"c\")\n", + "letters[0]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 159 + }, + "id": "3MERPn2I_o9D", + "outputId": "353f1a99-0e22-4353-9f24-537d0077cec4" + }, + "outputs": [], + "source": [ + "# но изменить элемент, как мы это делали в списке, нельзя\n", + "# letters[0] = \"d\" --> Error" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3AKPc8KEBKDl", + "outputId": "87e678c8-043c-4f31-cef1-75655c3ec8db" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['d', 'b', 'c']" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# для изменения элемента кортеж вначале нужно преобразовать в список\n", + "letters_list = list(letters)\n", + "letters_list[0] = \"d\"\n", + "letters_list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "NvRmYNY2C36p", + "outputId": "2c0a674d-e22c-4df9-b7e5-fc6faa7d995f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "tuple" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# кортеж из одного элемента можно создать с помощью запятой\n", + "letters_a: tuple[str] = (\"a\",)\n", + "type(letters_a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "D2vQPPY8C_2G", + "outputId": "a10456d8-ae19-4ed5-d5b3-8b44d8b3e29b" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "str" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если запятую не указывать, получится строка\n", + "a_let = \"a\"\n", + "type(a_let)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4VBqLLmkCyGB" + }, + "source": [ + "Функция enumerate()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2Al5QGWAC0sc", + "outputId": "827cc64c-71e4-48f1-cae6-cf6124d5505c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(0, 'Microsoft') \n", + "(1, 'Apple') \n", + "(2, 'Tesla') \n" + ] + } + ], + "source": [ + "companies: list[str] = [\"Microsoft\", \"Apple\", \"Tesla\"]\n", + "\n", + "# если записать результат функции enumerate() в одну переменную,\n", + "for company in enumerate(companies):\n", + "\n", + " # то мы получим кортежи\n", + " print(company, type(company))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OHyjLQYRL-lz" + }, + "source": [ + "Просмотр элементов словаря" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "LSkNG2x1MEWX" + }, + "outputs": [], + "source": [ + "shopping_dict: dict[str, int] = {\n", + " \"огурцы\": 2,\n", + " \"помидоры\": 3,\n", + " \"лук\": 1,\n", + " \"картофель\": 2,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "d_s5V8U6NFAL", + "outputId": "9b6ec1e0-25b0-4dce-b3d0-6bd0af6ea425" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('огурцы', 2)\n", + "('помидоры', 3)\n", + "('лук', 1)\n", + "('картофель', 2)\n" + ] + } + ], + "source": [ + "# то же самое со словарем и методом .items()\n", + "for item in shopping_dict.items():\n", + " print(item)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "GlSqhwQfJbCN" + }, + "source": [ + "Распаковка кортежей" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "h1hVafb_JaUn", + "outputId": "5692e7d9-0089-42d0-987a-b884b8b62c86" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n" + ] + } + ], + "source": [ + "# как и список, кортеж можно распаковать в несколько переменных\n", + "a_let, b_let, c_let = (\"a\", \"b\", \"c\")\n", + "print(a_let)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "BFtyYKARKQPT", + "outputId": "bb7ed4cf-d02a-4219-e998-f386324a03f4" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0 Microsoft\n", + "1 Apple\n", + "2 Tesla\n" + ] + } + ], + "source": [ + "companies = [\"Microsoft\", \"Apple\", \"Tesla\"]\n", + "\n", + "# распаковку в две переменные с функцией enumerate() мы делать уже умеем\n", + "for index, company_name in enumerate(companies):\n", + " print(index, company_name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pO8swT03UAeV", + "outputId": "0b68f3ab-bd57-4526-b439-9c913772ea6d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "огурцы 2\n", + "помидоры 3\n", + "лук 1\n", + "картофель 2\n" + ] + } + ], + "source": [ + "shopping_dict = {\n", + " \"огурцы\": 2,\n", + " \"помидоры\": 3,\n", + " \"лук\": 1,\n", + " \"картофель\": 2,\n", + "}\n", + "\n", + "# то же самое с ключами и значениями словаря\n", + "for key, value in shopping_dict.items():\n", + " print(key, value)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BZRw7ZcPCwGh" + }, + "source": [ + "Функция zip()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Ti6oDrQjCvhb", + "outputId": "bbb46ac5-a1fa-4925-cced-7e3f2cd4e52e" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 64, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если есть два и более списка\n", + "names = [\n", + " \"Артем\",\n", + " \"Антон\",\n", + " \"Александр\",\n", + " \"Борис\",\n", + " \"Виктор\",\n", + " \"Геннадий\",\n", + "]\n", + "income: list[int] = [97000, 110000, 95000, 84000, 140000, 120000]\n", + "\n", + "# функция zip() соединит первые элементы списков,\n", + "# вторые элементы списков и т.д.\n", + "zip(names, income)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "S84QKkqDHztA", + "outputId": "886a7956-4213-4349-fa15-8063782c15b3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[('Артем', 97000),\n", + " ('Антон', 110000),\n", + " ('Александр', 95000),\n", + " ('Борис', 84000),\n", + " ('Виктор', 140000),\n", + " ('Геннадий', 120000)]" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# для вывода результата нужно передать zip-объект в функцию list()\n", + "# на выходе мы получим список из кортежей\n", + "print(list(zip(names, income)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xLJn10TGXhlq" + }, + "source": [ + "### Множества" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "69RH3VDxWu_5" + }, + "source": [ + "Создание множества" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7T9QjMN_tn5Q", + "outputId": "67e65595-422c-408e-ec10-a86901243173" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "set() {'a', 'e', 'c', 'b', 'd'} {'a', 'b', 'c'}\n" + ] + } + ], + "source": [ + "# пустое множество задается через функцию set()\n", + "set_1: set[str] = set()\n", + "\n", + "# непустое множество задается через функцию set() и итератор\n", + "# например, список элементов или строку\n", + "set_2: set[str] = set(\"abcde\") # pylint: disable=W0130\n", + "\n", + "# или путем перечисления элементов в фигурных скобках {}\n", + "set_3: set[str] = {\"a\", \"b\", \"c\", \"c\"} # pylint: disable=W0130\n", + "\n", + "# множество содержит только уникальные элементы, поэтому дубликаты удаляются\n", + "print(set_1, set_2, set_3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "k4sVIWhxtn8N", + "outputId": "0d134a34-16ac-4421-c7fd-13c6492f55bc" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создать множество через пустые фигурные скобки нельзя\n", + "not_a_set: dict[str, str] = {}\n", + "\n", + "# так создается словарь\n", + "type(not_a_set)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "tHsQ7_dCXQkJ" + }, + "source": [ + "Добавление и удаление элементов" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "VMdDL588YmOm" + }, + "outputs": [], + "source": [ + "# предположим, что мы хотим создать множество гласных букв в русском языке\n", + "vowels: set[str] = {\"а\", \"о\", \"э\", \"е\", \"у\", \"ё\", \"ю\"}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "A3b7LnrTuxu9", + "outputId": "5a6319ac-77ea-435c-884d-b16b4e9f3649" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'а', 'е', 'о', 'у', 'э', 'ю', 'я', 'ё'}" + ] + }, + "execution_count": 69, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавим одну букву \"я\" методом .add()\n", + "vowels.add(\"я\")\n", + "vowels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RuCG-RnTk9SZ", + "outputId": "d18e632c-25d8-42a9-e441-084807cbcd20" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'а', 'е', 'и', 'о', 'у', 'ы', 'э', 'ю', 'я', 'ё'}" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавим две буквы \"и\" и \"ы\" методом .update()\n", + "vowels.update([\"и\", \"ы\"])\n", + "vowels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "6OJBJ5cYvwrl", + "outputId": "0693321a-76a4-4a8a-deda-d3c8b5abd101" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'а', 'е', 'и', 'о', 'у', 'щ', 'ы', 'э', 'ю', 'я', 'ё'}" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если по ошибке мы добавим согласную букву,\n", + "vowels.add(\"щ\")\n", + "vowels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VTCYCiXZv4Wc", + "outputId": "5698ddec-d2a8-4c89-e9d9-d8fc91fb6b2e" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'а', 'е', 'и', 'о', 'у', 'ы', 'э', 'ю', 'я', 'ё'}" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# ее можно удалить методом .remove()\n", + "vowels.remove(\"щ\")\n", + "vowels" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uB1je436aY19" + }, + "source": [ + "Теория множеств в Питоне" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ScRveXFjagly", + "outputId": "2767f29b-0f54-492d-f9dd-3a0cccbe6048" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# два множества равны, если содержат одинаковые элементы,\n", + "# при этом порядок элементов не важен\n", + "print({\"a\", \"b\", \"c\"} == {\"c\", \"b\", \"a\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "O5_E1AS9JOL2", + "outputId": "807df047-e851-4a72-9035-c72316d33b59" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# выведем мощность множества с помощью функции len()\n", + "print(len({\"a\", \"b\", \"c\"}))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tktbnMu4JOOY", + "outputId": "2f201ee0-3b16-4ff6-9121-de1f0155834f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# проверим, содержится ли элемент во множестве\n", + "print(\"a\" in {\"a\", \"b\", \"c\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7LjJsYc2JORQ", + "outputId": "3d5cd120-68d9-450c-ba02-c95fb0c3f051" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# возможна и обратная операция\n", + "print(\"a\" not in {\"a\", \"b\", \"c\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "MF1nGQvDJOUI", + "outputId": "95c006ba-48be-4766-fa53-293ecdb1ec27" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# проверим является ли А подмножеством В\n", + "set_a: set[str] = {\"a\", \"b\", \"c\"}\n", + "set_b: set[str] = {\"a\", \"b\", \"c\", \"d\", \"e\", \"f\"}\n", + "\n", + "set_a.issubset(set_b)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Ne2zLJy3DMT7", + "outputId": "96bcbed1-0112-40f7-f012-149a229f67af" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# проверим является ли B надмножеством А\n", + "set_b.issuperset(set_a)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0MxJj85iDc_y" + }, + "outputs": [], + "source": [ + "# даны участники команд по обработке естественного языка (nlp)\n", + "# и компьютерному зрению (cv)\n", + "nlp: set[str] = {\"Анна\", \"Николай\", \"Павел\", \"Оксана\"}\n", + "cv: set[str] = {\"Николай\", \"Евгений\", \"Ольга\", \"Оксана\"}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ipXl-eO5EFKS", + "outputId": "bc4c9d32-c49f-473e-ff79-5631038a2e61" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Павел', 'Евгений', 'Оксана', 'Николай', 'Анна', 'Ольга'}\n", + "{'Павел', 'Евгений', 'Оксана', 'Николай', 'Анна', 'Ольга'}\n" + ] + } + ], + "source": [ + "# найдем тех, кто работает или в nlp, или в cv, или в обеих командах\n", + "\n", + "# можно использовать метод .union()\n", + "print(nlp.union(cv))\n", + "\n", + "# или символ |\n", + "print(nlp | cv)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "vkUEl3eeEnPn", + "outputId": "3606efdb-d621-4268-b072-7c05e676054b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Оксана', 'Николай'}\n", + "{'Оксана', 'Николай'}\n" + ] + } + ], + "source": [ + "# найдем пересечение множеств, то есть тех, кто работает и в nlp, и в cv\n", + "print(nlp.intersection(cv))\n", + "print(nlp & cv)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "mNV8c0hQExzL", + "outputId": "0a71a036-d2a9-4728-9f4a-adff5df74b4b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Анна', 'Павел'}\n", + "{'Анна', 'Павел'}\n" + ] + } + ], + "source": [ + "# выведем тех, кто работает только в nlp, но не в cv или cv и nlp одновременно\n", + "print(nlp.difference(cv))\n", + "print(nlp - cv)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RnawDdtME8T4", + "outputId": "9691b8dd-bc78-428c-ec7f-322a316f33ba" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Евгений', 'Ольга'}\n", + "{'Евгений', 'Ольга'}\n" + ] + } + ], + "source": [ + "# выведем тех, кто работает только в cv,\n", + "# но не в nlp или nlp и cv одновременно\n", + "print(cv.difference(nlp))\n", + "print(cv - nlp)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "sHIWgu4ZFEqv", + "outputId": "8f8c106c-3186-4b23-f95c-5d508a708b65" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Павел', 'Евгений', 'Анна', 'Ольга'}\n", + "{'Павел', 'Евгений', 'Анна', 'Ольга'}\n" + ] + } + ], + "source": [ + "# найдем тех, кто работает или в cv, или в nlp,\n", + "# но не в обеих областях одновременно\n", + "print(nlp.symmetric_difference(cv))\n", + "print(nlp ^ cv)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8uLziVR-Z5mU" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/python/makarov/chapter_8_lists_tuples_sets.py b/python/makarov/chapter_8_lists_tuples_sets.py new file mode 100644 index 00000000..f18b969a --- /dev/null +++ b/python/makarov/chapter_8_lists_tuples_sets.py @@ -0,0 +1,537 @@ +"""Макаров. + +Списки, кортежи и множества. +""" + +# ## Списки, кортежи и множества + +# ### Списки + +# Основы работы со списками + +# + +# пустой список можно создать через [] или функцию list() +# импортируем класс стеммера и создаем объект + +# from nltk.stem import PorterStemmer + +some_list_1: list[str] = [] +some_list_2: list[str] = list() # pylint: disable=R1734 + +print(some_list_1, some_list_2) +# - + +# элементами списка могут, в частности, быть числа, строки, +# другие списки и словари +number_three: list[int | str | list[str] | dict[str, int]] = [ + 3, + "число три", + ["число", "три"], + {"число": 3}, +] +# number_three + +# длина списка рассчитывается через функцию len() +len(number_three) + +# Индекс и срез списка + +# + +# у списка есть положительный и отрицательный индексы +abc_list: list[str] = ["a", "b", "c", "d", "e"] + +# воспользуемся ими для вывода первого и последнего элементов +print(abc_list[0], abc_list[-1]) + +# + +# при работе с вложенным списком +salary_list: list[list[str | int]] = [ + ["Анна", 90000], + ["Игорь", 85000], + ["Алексей", 95000], +] + +# мы вначале указываем индекс вложенного списка, а затем индекс элемента в нем +# salary_list[1][0] +# - + +# индекс можно узнать с помощью метода .index() +abc_list.index("c") + +# метод .index() можно применить и ко вложенному списку +salary_list[0].index(90000) + +# + +# создадим список с днями недели +days_list: list[str] = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"] + +# и выведем со второго по пятый элемент включительно +# days_list[1:5] +# - + +# выведем каждый второй элемент в срезе с первого по пятый +# days_list[:5:2] + +# проверим есть ли "Пн" в списке +# "Пн" in days_list + +# если "Вт" есть в списке +if "Вт" in days_list: + + # выведем сообщение + print("Такое слово есть") + +# Добавление, замена и удаление элементов списка + +# создадим список +weekdays: list[str] = ["Понедельник", "Вторник"] + +# добавим один элемент в конец списка с помощью метода .append() +weekdays.append("Четверг") +# weekdays + +# добавим элемент в определенное место в списке +# через желаемый индекс этого элемента +weekdays.insert(2, "Среда") +# weekdays + +# изменим четвертый элемент в списке +weekdays[3] = "Пятница" +# weekdays + +# удалим элемент по его значению +weekdays.remove("Пятница") +# weekdays + +# удалим элемент по его индексу через ключевое слово del +del weekdays[2] +# weekdays + +# сделаем то же самое с помощью метода .pop() +# этот метод выводит удаляемый элемент +weekdays.pop(1) + +# посмотрим, что осталось в нашем списке +# weekdays + +# Сложение списков + +# + +# соединить два списка можно с помощью метода .extend() +more_weekdays: list[str] = ["Вторник", "Среда", "Четверг", "Пятница"] + +weekdays.extend(more_weekdays) +# weekdays + +# + +weekend: list[str] = ["Суббота", "Воскресенье"] + +# или просто сложив два списка +print(weekdays + weekend) +# - + +# иногда бывает полезно "размножить" элементы списка +print(["Понедельник"] * 2) + +# такие "произведения" также можно складывать +print(["Понедельник"] * 2 + ["Вторник"] * 2) + +# Распаковка списков + +# дан список +# "_" добавлен для того, чтобы избежать дублирования кода +# и как следствие ошибок pylint +week: list[str] = [ + "Понедельник_", + "Вторник_", + "Среда_", + "Четверг_", + "Пятница_", + "Суббота_", + "Воскресенье_", +] + +# указав индекс элемента, его можно записать в переменную +monday = week[0] +# monday + +# + +# срез можно поместить в несколько переменных +monday, tuesday, wednesday = week[:3] + +# важно, чтобы количество элементов среза было равно количеству переменных +# monday, tuesday, wednesday +# - + +# можно выделить первый элемент, а остальные поместить +# в переменную со звездочкой +monday, *rest = week +# monday + +# также можно поступить, например, с первым и последним элементом +monday, *days, sunday = week +# monday, sunday + +# посмотрим, какие элементы остались в переменной со звездочкой +# days + +# Сортировка списков + +# возьмем список чисел +nums: list[int] = [25, 10, 30, 20, 5, 15] + +# и отсортируем с помощью функции sorted(), результат выводится сразу +sorted(nums) + +# исходный список при этом не изменился +# nums + +# если поместить результат в переменную, изменения сохранятся +sorted_nums = sorted(nums) +# sorted_nums + +# метод .sort() сохраняет результат, но не выводит его сразу +# reverse = True задает сортировку по убыванию +nums.sort(reverse=True) + +# выведем результат +# nums + +# + +# метод .reverse() задает обратный порядок, сохраняет, но не выводит результат +nums.reverse() + +# его также нужно вывести отдельно +# nums +# - + +# функция reversed() возвращает итератор +reversed(nums) + +# вывести результат можно с помощью функции list() +list(reversed(nums)) + +# результат при этом не сохраняется +# nums + +# Преобразование списка в строку + +# дан список из строковых элементов +str_list: list[str] = ["P", "y", "t", "h", "o", "n"] + +# с помощью метода .join() можно соединить все элементы +joined_str = "".join(str_list) +# joined_str + +# если в кавычках ничего не указывать, элементы просто соединятся, +# но можно указать любой другой элемент +joined_str_ = "_".join(str_list) +# joined_str_ + +# Арифметика в списках + +# дан список чисел +nums_: list[int] = [3, 2, 1, 4, 5, 12, 3, 3, 7, 9, 11, 15] + +# с помощью метода .count() мы можем посчитать частоту вхождения +# элемента в список +nums_.count(3) + +# кроме того мы можем найти минимальное и максимальное значения +# и сумму элементов +print(min(nums_), max(nums_), sum(nums_)) + +# List comprehension + +# дан список имен +# оставим имена, начинающиеся с буквы "А" +names: list[str] = [ + "Артем", + "Антон", + "Александр", + "Борис", + "Виктор", + "Геннадий", +] + +# + +# вначале решим эту задачу с помощью цикла for + +# создадим пустой список +a_names: list[str] = [] + +# пройдемся по исходному списку в цикле for +for name in names: + + # с помощью метода .startswith() проверим, начинается ли слово с "А" + if name.startswith("А"): + + # если да, добавим в новый список + a_names.append(name) + +# выведем результат +# a_names +# - + +# эту же задачу можно решить через list comprehension +# по сути мы пишем: "что сделать, пока есть элемент в списке, при каком +# условии" +a_names = [name for name in names if name.startswith("А")] +# a_names + +# переведем все буквы в строчные, условие здесь не нужно +lower_names = [name.lower() for name in names] +# lower_names + +# схема условия if-else немного отличается +# оставляем имя, если это не Виктор, если Виктор - заменяем на Вадим +replace_name = [name if name != "Виктор" else "Вадим" for name in names] +# replace_name + +# + +# на занятии по обработке естественного языка с помощью list comprehension +# мы применили стеммер Портера к списку слов +lemmatized: list[str] = [ + "paris", + "visited", + "lot", + "museum", + "first", + "went", + "louvre", + "largest", + "art", + "museum", + "world", + "always", + "interested", + "art", + "spent", + "many", + "hour", + "museum", + "enormous", + "week", + "would", + "enough", +] + + +# porter = PorterStemmer() + +# применяем стеммер к элементу s, пока есть элементы s в списке lemmatized +# stemmed_p = [porter.stem(s) for s in lemmatized] +# print(stemmed_p) +# - + +# ### Кортежи + +# Основы работы с кортежами + +# пустой кортеж можно создать с помощью пустых круглых скобок () +# или функции tuple() +tuple_1: tuple[()] = () +tuple_2: tuple[str, ...] = tuple() +print(tuple_1, tuple_2) + +# в кортеже элементы упорядочены, а значит есть индекс +letters: tuple[str, ...] = ("a", "b", "c") +# letters[0] + +# + +# но изменить элемент, как мы это делали в списке, нельзя +# letters[0] = "d" --> Error +# - + +# для изменения элемента кортеж вначале нужно преобразовать в список +letters_list = list(letters) +# letters_list[0] = "d" +# letters_list + +# кортеж из одного элемента можно создать с помощью запятой +letters_a: tuple[str] = ("a",) +type(letters_a) + +# если запятую не указывать, получится строка +a_let = "a" +type(a_let) + +# Функция enumerate() + +# + +companies: list[str] = ["Microsoft", "Apple", "Tesla"] + +# если записать результат функции enumerate() в одну переменную, +for company in enumerate(companies): + + # то мы получим кортежи + print(company, type(company)) +# - + +# Просмотр элементов словаря + +shopping_dict: dict[str, int] = { + "огурцы": 2, + "помидоры": 3, + "лук": 1, + "картофель": 2, +} + +# то же самое со словарем и методом .items() +for item in shopping_dict.items(): + print(item) + +# Распаковка кортежей + +# как и список, кортеж можно распаковать в несколько переменных +a_let, b_let, c_let = ("a", "b", "c") +print(a_let) + +# + +companies = ["Microsoft", "Apple", "Tesla"] + +# распаковку в две переменные с функцией enumerate() мы делать уже умеем +for index, company_name in enumerate(companies): + print(index, company_name) + +# + +shopping_dict = { + "огурцы": 2, + "помидоры": 3, + "лук": 1, + "картофель": 2, +} + +# то же самое с ключами и значениями словаря +for key, value in shopping_dict.items(): + print(key, value) +# - + +# Функция zip() + +# + +# если есть два и более списка +names = [ + "Артем", + "Антон", + "Александр", + "Борис", + "Виктор", + "Геннадий", +] +income: list[int] = [97000, 110000, 95000, 84000, 140000, 120000] + +# функция zip() соединит первые элементы списков, +# вторые элементы списков и т.д. +zip(names, income) +# - + +# для вывода результата нужно передать zip-объект в функцию list() +# на выходе мы получим список из кортежей +print(list(zip(names, income))) + +# ### Множества + +# Создание множества + +# + +# пустое множество задается через функцию set() +set_1: set[str] = set() + +# непустое множество задается через функцию set() и итератор +# например, список элементов или строку +set_2: set[str] = set("abcde") # pylint: disable=W0130 + +# или путем перечисления элементов в фигурных скобках {} +set_3: set[str] = {"a", "b", "c", "c"} # pylint: disable=W0130 + +# множество содержит только уникальные элементы, поэтому дубликаты удаляются +print(set_1, set_2, set_3) + +# + +# создать множество через пустые фигурные скобки нельзя +not_a_set: dict[str, str] = {} + +# так создается словарь +type(not_a_set) +# - + +# Добавление и удаление элементов + +# предположим, что мы хотим создать множество гласных букв в русском языке +vowels: set[str] = {"а", "о", "э", "е", "у", "ё", "ю"} + +# добавим одну букву "я" методом .add() +vowels.add("я") +# vowels + +# добавим две буквы "и" и "ы" методом .update() +vowels.update(["и", "ы"]) +# vowels + +# если по ошибке мы добавим согласную букву, +vowels.add("щ") +# vowels + +# ее можно удалить методом .remove() +vowels.remove("щ") +# vowels + +# Теория множеств в Питоне + +# два множества равны, если содержат одинаковые элементы, +# при этом порядок элементов не важен +print({"a", "b", "c"} == {"c", "b", "a"}) + +# выведем мощность множества с помощью функции len() +print(len({"a", "b", "c"})) + +# проверим, содержится ли элемент во множестве +print("a" in {"a", "b", "c"}) + +# возможна и обратная операция +print("a" not in {"a", "b", "c"}) + +# + +# проверим является ли А подмножеством В +set_a: set[str] = {"a", "b", "c"} +set_b: set[str] = {"a", "b", "c", "d", "e", "f"} + +set_a.issubset(set_b) +# - + +# проверим является ли B надмножеством А +set_b.issuperset(set_a) + +# даны участники команд по обработке естественного языка (nlp) +# и компьютерному зрению (cv) +nlp: set[str] = {"Анна", "Николай", "Павел", "Оксана"} +cv: set[str] = {"Николай", "Евгений", "Ольга", "Оксана"} + +# + +# найдем тех, кто работает или в nlp, или в cv, или в обеих командах + +# можно использовать метод .union() +print(nlp.union(cv)) + +# или символ | +print(nlp | cv) +# - + +# найдем пересечение множеств, то есть тех, кто работает и в nlp, и в cv +print(nlp.intersection(cv)) +print(nlp & cv) + +# выведем тех, кто работает только в nlp, но не в cv или cv и nlp одновременно +print(nlp.difference(cv)) +print(nlp - cv) + +# выведем тех, кто работает только в cv, +# но не в nlp или nlp и cv одновременно +print(cv.difference(nlp)) +print(cv - nlp) + +# найдем тех, кто работает или в cv, или в nlp, +# но не в обеих областях одновременно +print(nlp.symmetric_difference(cv)) +print(nlp ^ cv) diff --git a/python/makarov/chapter_9_dictionaries.ipynb b/python/makarov/chapter_9_dictionaries.ipynb new file mode 100644 index 00000000..3fc23ade --- /dev/null +++ b/python/makarov/chapter_9_dictionaries.ipynb @@ -0,0 +1,2750 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\"\"\"Макаров.\n", + "\n", + "Словарь в Питоне\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0AoPSXyUTTLc" + }, + "source": [ + "## Словарь в Питоне" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lIM5gFo4TbUg" + }, + "source": [ + "### Понятие словаря" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AEHY4SW_3mIj" + }, + "source": [ + "#### Создание словаря" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "x3wxNu5jthst", + "outputId": "eedbd51a-e6ce-4a0f-ac35-7d57c4cc59ef" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{} {}\n" + ] + } + ], + "source": [ + "# пустой словарь можно создать с помощью {} или функции dict()\n", + "# импортируем класс Counter\n", + "from collections import Counter\n", + "\n", + "# импортируем функцию pprint() из модуля pprint\n", + "# некоторые структуры данных она выводит лучше, чем обычная print()\n", + "from pprint import pprint\n", + "\n", + "import numpy as np\n", + "\n", + "dict_1: dict[str, str] = {}\n", + "dict_2: dict[str, str] = dict() # pylint: disable=R1735\n", + "print(dict_1, dict_2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tLWO1t--thwP", + "outputId": "c802fcb0-3757-40ab-94c2-44fae324b0db" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'name': 'Toyota', 'founded': 1937, 'founder': 'Kiichiro Toyoda'}" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# словарь можно сразу заполнить ключами и значениями\n", + "company: dict[str, str | int] = {\n", + " \"name\": \"Toyota\",\n", + " \"founded\": 1937,\n", + " \"founder\": \"Kiichiro Toyoda\",\n", + "}\n", + "company" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pBONkfBYZRkZ", + "outputId": "f364cd9b-bbac-4011-e7f4-069889ac14df" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'TYO': 'Toyota', 'TSLA': 'Tesla', 'F': 'Ford'}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# словарь можно создать из вложенных списков\n", + "tickers: dict[str, str] = dict([[\"TYO\", \"Toyota\"], [\"TSLA\", \"Tesla\"], [\"F\", \"Ford\"]])\n", + "tickers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "y5zC4qKWbUn3", + "outputId": "becdc0ee-1018-4dee-d6e9-9a861791c5c7" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'k1': 0, 'k2': 0, 'k3': 0}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если поместить ключи в кортеж\n", + "keys: tuple[str, ...] = (\"k1\", \"k2\", \"k3\")\n", + "# и задать значение\n", + "value_global = 0\n", + "\n", + "# то с помощью метода .fromkeys() можно создать словарь\n", + "# с этими ключами и заданным значением для каждого из них\n", + "empty_values = dict.fromkeys(keys, value_global)\n", + "empty_values" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SdW5ePii6BGZ" + }, + "source": [ + "#### Ключи и значения словаря" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "W9vaAXb2zKVb" + }, + "source": [ + "Виды значений словаря" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "d0bh3eRu6EAy", + "outputId": "ef5c819c-8445-4b53-d843-19154d4f3e47" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'k1': 123,\n", + " 'k2': 'string',\n", + " 'k3': nan,\n", + " 'k4': True,\n", + " 'k5': None,\n", + " 'k6': [1, 2, 3],\n", + " 'k7': array([1, 2, 3]),\n", + " 'k8': {1: 'v1', 2: 'v2', 3: 'v3'}}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# приведем пример того, какими могут быть значения словаря\n", + "value_types: dict[str, int | str | bool | None | list[int] | object | float] = {\n", + " \"k1\": 123,\n", + " \"k2\": \"string\",\n", + " \"k3\": np.nan, # тип \"Пропущенное значение\"\n", + " \"k4\": True, # логическое значение\n", + " \"k5\": None,\n", + " \"k6\": [1, 2, 3],\n", + " \"k7\": np.array([1, 2, 3]),\n", + " \"k8\": {1: \"v1\", 2: \"v2\", 3: \"v3\"},\n", + "}\n", + "\n", + "value_types" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AktD-qd772bs" + }, + "source": [ + "Методы .keys(), .values() и .items()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FoLHc64C716M" + }, + "outputs": [], + "source": [ + "# создадим несложный словарь с информацией о сотруднике\n", + "person: dict[str, str | int | list[str]] = {\n", + " \"first name\": \"Иван\",\n", + " \"last name\": \"Иванов\",\n", + " \"born\": 1980,\n", + " \"dept\": \"IT\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8Gl7ZMqt8wuZ", + "outputId": "708807b9-c8e5-478c-ac25-baee23c1a0ad" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_keys(['first name', 'last name', 'born', 'dept'])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# посмотрим на ключи и\n", + "print(person.keys())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "j3mruPRR8xgX", + "outputId": "06bbf715-5091-45c5-d84a-8bfcdefdcf76" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_values(['Иван', 'Иванов', 1980, 'IT'])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# значения\n", + "print(person.values())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wfmjr1bu81Ay", + "outputId": "53c39b8e-dc1f-4be5-800b-97f534efc66c" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_items([('first name', 'Иван'), ('last name', 'Иванов'), ('born', 1980), ('dept', 'IT')])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# а также на пары ключ-значение в виде списка из кортежей\n", + "print(person.items())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YxrdHML389v4" + }, + "source": [ + "Использование цикла for" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ssN6LrjO83h8", + "outputId": "1d079d55-69b3-4f88-8f58-d34896f7945e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "first name Иван\n", + "last name Иванов\n", + "born 1980\n", + "dept IT\n" + ] + } + ], + "source": [ + "# ключи и значения можно вывести в цикле for\n", + "for key, value_p in person.items():\n", + " print(key, value_p)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zU-JtgYJ-vyO" + }, + "source": [ + "Доступ по ключу и метод .get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "Au-MDTwZ-tGI", + "outputId": "3ba22481-65b9-43b9-8be3-e68bc38d87a1" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'Иванов'" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# значение можно посмотреть по ключу\n", + "person[\"last name\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 159 + }, + "id": "XwWDSYzH-O0l", + "outputId": "dbc6b773-bbcd-45f9-c0ac-bab705e05338" + }, + "outputs": [ + { + "ename": "KeyError", + "evalue": "'education'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\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[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mperson\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'education'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m: 'education'" + ] + } + ], + "source": [ + "# если такого ключа нет, Питон выдаст ошибку\n", + "# person['education'] --> Error" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "dx2nFVH7eils", + "outputId": "b9ff14d3-4bea-41c7-b838-4560ddd3d228" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "None\n" + ] + } + ], + "source": [ + "# чтобы этого не произошло, можно использовать метод .get()\n", + "# по умолчанию при отсутствии ключа он выводит значение None\n", + "print(person.get(\"education\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qTovRCnIb1ei", + "outputId": "e0bbb24f-00fb-4c43-f611-fc4ad8866598" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1980" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если ключ все-таки есть, .get() выведет соответствующее значение\n", + "print(person.get(\"born\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IBgf5Al-aCOK" + }, + "source": [ + "Проверка вхождения ключа и значения в словарь" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XbRxj_nPaHJU", + "outputId": "faa46646-4e20-432b-dbe8-c68e06ff9699" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# проверим есть ли такой ключ\n", + "print(\"born\" in person)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "sAKfv79KbC1p", + "outputId": "3f9562bd-fab8-4a29-abee-ec82d9d85fae" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# и такое значение\n", + "print(1980 in person.values())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "UelKiVrybH30", + "outputId": "0f5eacb2-eb21-4ef2-b818-9e66500e1227" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# можно также проверить наличие и ключа, и значения одновременно\n", + "print((\"born\", 1980) in person.items())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kY91ANMfXeRG" + }, + "source": [ + "### Операции со словарями" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ebptqYBRcrJp" + }, + "source": [ + "#### Добавление и изменение элементов" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qVBaa3SrtlYB", + "outputId": "83fbde38-1fff-4e8c-c2c5-5de94465eca9" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'first name': 'Иван',\n", + " 'last name': 'Иванов',\n", + " 'born': 1980,\n", + " 'dept': 'IT',\n", + " 'languages': ['Python', 'C++']}" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавить элемент можно, передав новому ключу новое значение\n", + "# обратите внимание, в данном случае новое значение - это список\n", + "person[\"languages\"] = [\"Python\", \"C++\"]\n", + "person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Vv-okCt8tlau", + "outputId": "74f5f097-72cc-4539-ba8c-f4baf7223a83" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'first name': 'Иван',\n", + " 'last name': 'Иванов',\n", + " 'born': 1980,\n", + " 'dept': 'IT',\n", + " 'languages': ['Python']}" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# изменить элемент можно, передав существующему ключу новое значение,\n", + "# значение - это по-прежнему список, но из одного элемента\n", + "person[\"languages\"] = [\"Python\"]\n", + "person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FBO1GOoDHXjc", + "outputId": "87efcd08-cdd8-47cb-ac39-52807319d17c" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'first name': 'Иван',\n", + " 'last name': 'Иванов',\n", + " 'born': 1980,\n", + " 'dept': 'IT',\n", + " 'languages': ['Python'],\n", + " 'job': 'программист',\n", + " 'experience': 7}" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# возьмем еще один словарь\n", + "new_elements: dict[str, str | int] = {\"job\": \"программист\", \"experience\": 7}\n", + "\n", + "# и присоединим его к существующему словарю с помощью метода .update()\n", + "person.update(new_elements)\n", + "person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8ABSReiDS86F", + "outputId": "f7c2c895-86fc-451c-a619-56514d1b4ad2" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'first name': 'Иван',\n", + " 'last name': 'Иванов',\n", + " 'born': 1980,\n", + " 'dept': 'IT',\n", + " 'languages': ['Python'],\n", + " 'job': 'программист',\n", + " 'experience': 7}" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# метод .setdefault() проверит есть ли ключ в словаре,\n", + "# если \"да\", значение не изменится\n", + "person.setdefault(\"last name\", \"Петров\")\n", + "person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uq1eR4FEYIFx", + "outputId": "b9ca0002-c8bc-458c-b978-c86413159dfb" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'first name': 'Иван',\n", + " 'last name': 'Иванов',\n", + " 'born': 1980,\n", + " 'dept': 'IT',\n", + " 'languages': ['Python'],\n", + " 'job': 'программист',\n", + " 'experience': 7,\n", + " 'f_languages': ['русский', 'английский']}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# если нет, будет добавлен новый ключ и соответствующее значение\n", + "person.setdefault(\"f_languages\", [\"русский\", \"английский\"])\n", + "person" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wUMTWNK-fFsd" + }, + "source": [ + "#### Удаление элементов" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "AKViA8ItfIye", + "outputId": "037a5a8d-0b08-4c4a-aec2-29e4eea7e49e" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "'IT'" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# метод .pop() удаляет элемент по ключу и выводит удаляемое значение\n", + "print(person.pop(\"dept\"))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "anOK_5RVh8eG", + "outputId": "9a696c51-117c-42cc-aa12-3049452b3111" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'first name': 'Иван',\n", + " 'last name': 'Иванов',\n", + " 'born': 1980,\n", + " 'languages': ['Python'],\n", + " 'job': 'программист',\n", + " 'experience': 7,\n", + " 'f_languages': ['русский', 'английский']}" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# мы видим, что пары 'dept' : 'IT' больше нет\n", + "person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "t6flk9z_fluM" + }, + "outputs": [], + "source": [ + "# ключевое слово del также удаляет элемент по ключу\n", + "# удаляемое значение не выводится\n", + "del person[\"born\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "6aruZx9MKBUK", + "outputId": "0334ba54-fb22-460f-a83a-99ce528947be" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('f_languages', ['русский', 'английский'])" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# метод .popitem() удаляет последний добавленный элемент и выводит его\n", + "person.popitem()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tH_TmTAgf1Qc", + "outputId": "77b794f7-1026-4973-b30b-835773e2aa9d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# метод .clear() удаляет все элементы словаря\n", + "person.clear()\n", + "person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "KQzvF_SmHFYa" + }, + "outputs": [], + "source": [ + "# ключевое слово del также позволяет удалить словарь целиком\n", + "del person" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 159 + }, + "id": "41jpFZaGA3U3", + "outputId": "659769e5-c524-40b6-cc40-e0253b2ab52f" + }, + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'person' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\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[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mperson\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;31mNameError\u001b[0m: name 'person' is not defined" + ] + } + ], + "source": [ + "# убедимся, что такого словаря больше нет\n", + "person" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VS8k8X8kwAhj" + }, + "source": [ + "#### Сортировка словарей" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "u3rg89UKwE1e" + }, + "outputs": [], + "source": [ + "# возьмем несложный словарь\n", + "dict_to_sort: dict[str, int] = {\"k2\": 30, \"k1\": 20, \"k3\": 10}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bTwIep0qwFW8", + "outputId": "117cde36-cd88-49b3-ba59-7b52cb3e70d1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['k1', 'k2', 'k3']" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# отсортируем ключи\n", + "sorted(dict_to_sort)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tnJvCeBxna2q", + "outputId": "544cdf21-7661-4fb1-cdcb-c1d39fec5eab" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[10, 20, 30]" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# и значения\n", + "sorted(dict_to_sort.values())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "jYQNHiJrMhSA", + "outputId": "cbfcc983-24f9-4c9f-bea1-f2c5dcfd806d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "dict_items([('k2', 30), ('k1', 20), ('k3', 10)])" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# посмотрим на пары ключ : значение\n", + "dict_to_sort.items()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "2Lbe96f0nh85", + "outputId": "3a86244b-ab49-4aad-b350-58d7abd88883" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[('k1', 20), ('k2', 30), ('k3', 10)]" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# для их сортировки по ключу (индекс [0])\n", + "# воспользуемся методом .items() и lambda-функцией\n", + "sorted(dict_to_sort.items(), key=lambda item: item[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Vl9gs9fVoE-A", + "outputId": "bd90cb3f-4e6a-4c6f-91e8-77b84df8b85f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[('k3', 10), ('k1', 20), ('k2', 30)]" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# сортировка по значению выполняется так же, однако\n", + "# lambda-функции мы передаем индекс [1]\n", + "sorted(dict_to_sort.items(), key=lambda item: item[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "v9aK8-q2CdXO" + }, + "source": [ + "#### Копирование словарей" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ysVmXSyVFZMU" + }, + "outputs": [], + "source": [ + "# создадим исходный словарь с количеством студентов на первом и втором курсах университета\n", + "original: dict[str, int] = {\"Первый курс\": 174, \"Второй курс\": 131}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DYkMoaN3GL1X" + }, + "source": [ + "Копирование с помощью метода .copy()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-t7mXlsUCc2p", + "outputId": "877c2f4b-629f-48d4-cca6-3a0fa71151f1" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'Первый курс': 174, 'Второй курс': 131}\n", + "{'Первый курс': 174, 'Второй курс': 131, 'Третий курс': 117}\n" + ] + } + ], + "source": [ + "# создадим копию этого словаря с помощью метода .copy()\n", + "new_1 = original.copy()\n", + "\n", + "# добавим информацию о третьем курсе в новый словарь\n", + "new_1[\"Третий курс\"] = 117\n", + "\n", + "# исходный словарь не изменился\n", + "print(original)\n", + "print(new_1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "h9IslECkGSsr" + }, + "source": [ + "Копирование через оператор присваивания `=` (так делать не стоит!)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cQZ-uDDpEvkO", + "outputId": "99f751ae-396c-4a2c-ffd8-f06a75b6bb57" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{}\n", + "{}\n" + ] + } + ], + "source": [ + "# передадим исходный словарь в новую переменную\n", + "new_2 = original\n", + "\n", + "# удалим элементы нового словаря\n", + "new_2.clear()\n", + "\n", + "# из исходного словаря данные также удалились\n", + "print(original)\n", + "print(new_2)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3iDksQfFNiux" + }, + "source": [ + "### Функция `dir()`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nv3sToYdNmTd", + "outputId": "10c4048b-b1b3-471f-838d-9d211546fee3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['__class__',\n", + " '__class_getitem__',\n", + " '__contains__',\n", + " '__delattr__',\n", + " '__delitem__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__']" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# функция dir() возвращает все методы передаваемого ей объекта\n", + "some_dict = {\"k\": 1}\n", + "\n", + "# вначале идут специальные методы,\n", + "# они начинаются и заканчиваются символом '__'\n", + "# выведем первые 11 элементов\n", + "print(dir(some_dict)[:11])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "UkqCOYF0su5e", + "outputId": "7074b3c3-e901-44d7-bd5a-9b8d3d865a3a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'k': 1}\n" + ] + } + ], + "source": [ + "# когда мы передаем наш словарь функции print(),\n", + "print(some_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "BGLlQ1PhqEKF", + "outputId": "cf166c59-ba9f-4f1c-d1ac-6b7ec6ce0a57" + }, + "outputs": [ + { + "data": { + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + }, + "text/plain": [ + "\"{'k': 1}\"" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# на самом деле мы применяем к объекту метод .__str__()\n", + "some_dict.__str__() # pylint: disable=C2801" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "s2PqsanmtAE4", + "outputId": "eb3b4328-96cf-4339-8c4b-365948c4834c" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['clear',\n", + " 'copy',\n", + " 'fromkeys',\n", + " 'get',\n", + " 'items',\n", + " 'keys',\n", + " 'pop',\n", + " 'popitem',\n", + " 'setdefault',\n", + " 'update',\n", + " 'values']" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# в большинстве случаев нас будут интересовать методы без '__'\n", + "methods = dir(some_dict)[-11:]\n", + "\n", + "print(methods)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7fi2zJoGvh5v" + }, + "source": [ + "### Dict comprehension" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Qr-HfxbHv_if" + }, + "outputs": [], + "source": [ + "# создадим еще один несложный словарь\n", + "source_dict: dict[str, int] = {\"k1\": 2, \"k2\": 4, \"k3\": 6}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "wqP1P4EcwAC4", + "outputId": "af999e25-fed2-4303-e69a-182fdab468f5" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'k1': 4, 'k2': 8, 'k3': 12}" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# с помощью dict comprehension умножим каждое значение на два\n", + "new_source_dict = {key: value * 2 for (key, value) in source_dict.items()}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "l1w42uT0Kf1b", + "outputId": "906ee62e-c5d0-498c-d6ff-ba99c4352f14" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'K1': 2, 'K2': 4, 'K3': 6}" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# сделаем символы всех ключей заглавными\n", + "new_source_dict = {key.upper(): value for (key, value) in source_dict.items()}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "XKoh7SUJ5S8z", + "outputId": "785a0735-56eb-4599-8a1c-ac788c8f7dce" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'k2': 4}" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавим условие, что значение должно быть больше двух И меньше шести\n", + "new_dict_1 = {\n", + " key: value for (key, value) in source_dict.items() if value > 2 if value < 6\n", + "}\n", + "\n", + "print(new_dict_1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "I1nyzDSi6V3Y", + "outputId": "72f66774-7065-4815-d211-ef06ebd318ee" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'k2': 4}" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_dict: dict[str, int] = {}\n", + "\n", + "# при решении этой же задачи в цикле for\n", + "for key, value in source_dict.items():\n", + "\n", + " # мы бы использовали логическое И (and)\n", + " if 2 < value < 6:\n", + "\n", + " # если условия верны, записываем ключ и значение в новый словарь\n", + " new_dict[key] = value\n", + "\n", + "new_dict" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-rJUlsr563N7", + "outputId": "00c0b343-8ccb-4cfb-9ef3-f5568de87730" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'k1': 'even', 'k2': 'even', 'k3': 'even'}" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# условие с if-else ставится в самом начале схемы dict comprehension\n", + "# заменим значение на слово even, если оно четное, и odd, если нечетное\n", + "even_odd_dict: dict[str, str] = {\n", + " key: (\"even\" if value % 2 == 0 else \"odd\") for (key, value) in source_dict.items()\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3sCsWyonkkGM", + "outputId": "3dacd13e-10d3-44a7-8f23-3898e5840d13" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'k1': 0, 'k2': 0, 'k3': 0}" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# dict comprehension можно использовать вместо метода .fromkeys()\n", + "keys = (\"k1\", \"k2\", \"k3\")\n", + "\n", + "# передадим словарю ключи из кортежа keys и зададим значение 0 каждому из них\n", + "zeros_dict = {key: 0 for key in keys}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HplemEzXwNw0" + }, + "source": [ + "### Дополнительные примеры" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9I3D7qej8JFO" + }, + "source": [ + "#### lambda-функции, функции `map()` и `zip()`" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NQxOQz-_jilk" + }, + "source": [ + "Пример со списком" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZXoJ1TMsh13z" + }, + "outputs": [], + "source": [ + "# возьмем список слов\n", + "words: list[str] = [\"apple\", \"banana\", \"fig\", \"blackberry\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "BSyuvd278UPf", + "outputId": "4e410273-cca8-475f-e132-b2809c9ee789" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[5, 6, 3, 10]" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим lambda-функцию, которая посчитает длину передаваемого ей слова\n", + "# с помощью функции map() применим lambda-функцию\n", + "# к каждому элементу списка words\n", + "# и поместим длины слов в новый список length с помощью функции list()\n", + "length = list(map(len, words))\n", + "length" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "b0JRdAJHh2df", + "outputId": "5eda6227-fd0c-4170-c487-81c10956a8db" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'apple': 5, 'banana': 6, 'fig': 3, 'blackberry': 10}" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# с помощью функции zip() поэлементно соединим оба списка и\n", + "# преобразуем в словарь\n", + "from_zip_dict = dict(zip(words, length))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "kYNYaOQ-9-V6", + "outputId": "f3887c5f-3134-4c9f-cba7-9e55f340e20d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'apple': 5, 'banana': 6, 'fig': 3, 'blackberry': 10}" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# то же самое можно сделать с помощью функции zip() и list comprehension\n", + "zip_length_dict = dict(zip(words, [len(word) for word in words]))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PUs12XYyjmBh" + }, + "source": [ + "Пример со словарем" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0ZVWDzRMjo-6" + }, + "outputs": [], + "source": [ + "# возьмем словарь с ростом людей в футах\n", + "height_feet: dict[str, float] = {\"Alex\": 6.1, \"Jerry\": 5.4, \"Ben\": 5.8}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "irwOj3Rt_M1e", + "outputId": "3f5be590-39ab-4dbf-b475-4ab6afc82d7a" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[1.85928, 1.6459200000000003, 1.76784]" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# для преобразования футов в метры создадим lambda-функцию lambda m: m * 0.3048\n", + "# применим эту функцию к значениям словаря с помощью функции map()\n", + "# преобразуем в список\n", + "metres = list(map(lambda m: m * 0.3048, height_feet.values()))\n", + "metres" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "RcqkuR4WjsnB", + "outputId": "74026d78-3508-4898-9502-70f84f556a5d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'Alex': 1.86, 'Jerry': 1.65, 'Ben': 1.77}" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# с помощью функции zip() соединим ключи исходного словаря с элементами списка metres\n", + "dict(zip(height_feet.keys(), np.round(metres, 2)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "pxqmUJG7CEtO", + "outputId": "b3ee3331-c47a-42ac-ac3c-17f82987d4d3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "{'Alex': 1.86, 'Jerry': 1.65, 'Ben': 1.77}" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# то же самое можно выполнить с помощью dict comprehensions\n", + "# всего в одну строчку\n", + "# мы просто преобразуем значения словаря в метры\n", + "students_heights_dict = {\n", + " key: np.round(value * 0.3048, 2) for (key, value) in height_feet.items()\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "I-UUEhQNvezN" + }, + "source": [ + "#### Вложенные словари" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OA69rLjwwTAc" + }, + "outputs": [], + "source": [ + "# возьмем словарь, ключами которого будут id сотрудников\n", + "employees: dict[str, dict[str, str | int | float]] = {\n", + " \"id1\": {\n", + " \"first name\": \"Александр\",\n", + " \"last name\": \"Иванов\",\n", + " \"age\": 30,\n", + " \"job\": \"программист\",\n", + " },\n", + " \"id2\": {\n", + " \"first name\": \"Ольга\",\n", + " \"last name\": \"Петрова\",\n", + " \"age\": 35,\n", + " \"job\": \"ML-engineer\",\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "8UNwQKCANq0J", + "outputId": "a9831ab9-878a-4201-dc20-1d0a741eca26" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'first name': 'Александр', 'last name': 'Иванов', 'age': 30, 'job': 'программист'}\n", + "{'first name': 'Ольга', 'last name': 'Петрова', 'age': 35, 'job': 'ML-engineer'}\n" + ] + } + ], + "source": [ + "# а значениями - вложенные словари с информацией о них\n", + "for value_e in employees.values():\n", + " print(value_e)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xBRzL0hdkF95" + }, + "source": [ + "##### Базовый операции" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0Hx_jDxnOBF3", + "outputId": "c7767b24-5831-436b-cd71-d04d2917a9aa" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "30" + ] + }, + "execution_count": 60, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# для того чтобы вывести значение элемента вложенного словаря,\n", + "# воспользуемся двойным ключом\n", + "print(employees[\"id1\"][\"age\"])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "iUNy0ji7ORNC", + "outputId": "8e0c2822-2aac-4c93-9998-3c9547edf06e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id1': {'age': 30,\n", + " 'first name': 'Александр',\n", + " 'job': 'программист',\n", + " 'last name': 'Иванов'},\n", + " 'id2': {'age': 35,\n", + " 'first name': 'Ольга',\n", + " 'job': 'ML-engineer',\n", + " 'last name': 'Петрова'},\n", + " 'id3': {'age': 27,\n", + " 'first name': 'Дарья',\n", + " 'job': 'веб-дизайнер',\n", + " 'last name': 'Некрасова'}}\n" + ] + } + ], + "source": [ + "# добавим информацию о новом сотруднике\n", + "employees[\"id3\"] = {\n", + " \"first name\": \"Дарья\",\n", + " \"last name\": \"Некрасова\",\n", + " \"age\": 27,\n", + " \"job\": \"веб-дизайнер\",\n", + "}\n", + "\n", + "# и выведем обновленный словарь с помощью функции pprint()\n", + "pprint(employees)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "mHmC4hPGwTC_", + "outputId": "897b5449-4fed-4df6-a538-be532c3c6fcf" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id1': {'age': 30,\n", + " 'first name': 'Александр',\n", + " 'job': 'программист',\n", + " 'last name': 'Иванов'},\n", + " 'id2': {'age': 35,\n", + " 'first name': 'Ольга',\n", + " 'job': 'ML-engineer',\n", + " 'last name': 'Петрова'},\n", + " 'id3': {'age': 26,\n", + " 'first name': 'Дарья',\n", + " 'job': 'веб-дизайнер',\n", + " 'last name': 'Некрасова'}}\n" + ] + } + ], + "source": [ + "# изменить значение вложенного словаря можно также с помощью двойного ключа\n", + "employees[\"id3\"][\"age\"] = 26\n", + "pprint(employees)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "kP8KzxtckMf0" + }, + "source": [ + "##### Циклы `for`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rfKMVzEGlUf1", + "outputId": "7567b97d-4963-4dc8-eb09-73d2c84d9775" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id1': {'age': 30.0,\n", + " 'first name': 'Александр',\n", + " 'job': 'программист',\n", + " 'last name': 'Иванов'},\n", + " 'id2': {'age': 35.0,\n", + " 'first name': 'Ольга',\n", + " 'job': 'ML-engineer',\n", + " 'last name': 'Петрова'},\n", + " 'id3': {'age': 26.0,\n", + " 'first name': 'Дарья',\n", + " 'job': 'веб-дизайнер',\n", + " 'last name': 'Некрасова'}}\n" + ] + } + ], + "source": [ + "# заменим тип данных в информации о возрасте с int на float\n", + "\n", + "# для этого вначале пройдемся по вложенным словарям,\n", + "# т.е. по значениям info внешнего словаря employees\n", + "for info in employees.values():\n", + "\n", + " # затем по ключам и значениям вложенного словаря info\n", + " for key_info, value_info in info.items():\n", + "\n", + " # если ключ совпадет со словом 'age'\n", + " if key_info == \"age\":\n", + "\n", + " # преобразуем значение в тип float\n", + " info[key_info] = float(value_info)\n", + "\n", + "pprint(employees)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HO97JxkUkZyR" + }, + "source": [ + "##### Вложенные словари и dict comprehension" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-lBSDGLtm62e", + "outputId": "11b6677f-5514-4a7f-c868-7959c26b0e3a" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id1': {'age': 30.0,\n", + " 'first name': 'Александр',\n", + " 'job': 'программист',\n", + " 'last name': 'Иванов'},\n", + " 'id2': {'age': 35.0,\n", + " 'first name': 'Ольга',\n", + " 'job': 'ML-engineer',\n", + " 'last name': 'Петрова'},\n", + " 'id3': {'age': 26.0,\n", + " 'first name': 'Дарья',\n", + " 'job': 'веб-дизайнер',\n", + " 'last name': 'Некрасова'}}\n" + ] + } + ], + "source": [ + "# преоразуем обратно из float в int, но уже через dict comprehension\n", + "# для начала просто выведем словарь employees без изменений\n", + "pprint({id: info for id, info in employees.items()})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "qaPZCn-PnHpn", + "outputId": "38d50011-d70a-4cc0-b366-21a5fb6dc926" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id1': {'age': 30,\n", + " 'first name': 'Александр',\n", + " 'job': 'программист',\n", + " 'last name': 'Иванов'},\n", + " 'id2': {'age': 35,\n", + " 'first name': 'Ольга',\n", + " 'job': 'ML-engineer',\n", + " 'last name': 'Петрова'},\n", + " 'id3': {'age': 26,\n", + " 'first name': 'Дарья',\n", + " 'job': 'веб-дизайнер',\n", + " 'last name': 'Некрасова'}}\n" + ] + } + ], + "source": [ + "# а затем заменим значение внешнего словаря info (т.е. вложенный словарь)\n", + "# на еще один dict comprehension с условием if-else\n", + "pprint(\n", + " {\n", + " id: {\n", + " key: (int(value_i) if key == \"age\" else value_i)\n", + " for key, value_i in info.items()\n", + " }\n", + " for id, info in employees.items()\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KQw8_33YMLU2" + }, + "source": [ + "#### Частота слов в тексте" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ysL5RwJEMO7M" + }, + "outputs": [], + "source": [ + "# возьмем знакомый нам текст\n", + "corpus = (\n", + " \"When we were in Paris we visited a lot of museums. \"\n", + " \"We first went to the Louvre, the largest art museum in the world.\"\n", + " \"I have always been interested in art so I spent many hours there. \"\n", + " \"The museum is enormous, so a week there would not be enough.\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vu3yQDqNRb9o" + }, + "source": [ + "##### Предварительная обработка текста" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Y0Q0RhvlRRqJ", + "outputId": "d3ec9c90-e0b7-430b-b636-4bc33801ff6b" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['When', 'we', 'were', 'in', 'Paris', 'we', 'visited', 'a', 'lot', 'of', 'museums.', 'We', 'first', 'went', 'to', 'the', 'Louvre,', 'the', 'largest', 'art', 'museum', 'in', 'the', 'world.', 'I', 'have', 'always', 'been', 'interested', 'in', 'art', 'so', 'I', 'spent', 'many', 'hours', 'there.', 'The', 'museum', 'is', 'enourmous,', 'so', 'a', 'week', 'there', 'would', 'not', 'be', 'enough.']\n" + ] + } + ], + "source": [ + "# разделим его на слова\n", + "words = corpus.split()\n", + "print(words)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VPFYOtFWXmm2", + "outputId": "c3c416a3-d537-40d8-e823-6c81c3f4b72e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['when', 'we', 'were', 'in', 'paris', 'we', 'visited', 'a', 'lot', 'of', 'museums', 'we', 'first', 'went', 'to', 'the', 'louvre', 'the', 'largest', 'art', 'museum', 'in', 'the', 'world', 'i', 'have', 'always', 'been', 'interested', 'in', 'art', 'so', 'i', 'spent', 'many', 'hours', 'there', 'the', 'museum', 'is', 'enourmous', 'so', 'a', 'week', 'there', 'would', 'not', 'be', 'enough']\n" + ] + } + ], + "source": [ + "# с помощью list comprehension удалим точки, запятые\n", + "# и переведем все слова в нижний регистр\n", + "words = [word.strip(\".\").strip(\",\").lower() for word in words]\n", + "print(words)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JvApRTwkRfaS" + }, + "source": [ + "##### Способ 1. Условие if-else" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0FbwZ4ODSlxH", + "outputId": "8c0b1ea0-041d-4ee3-cae7-46a191f0a546" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[('the', 4), ('we', 3), ('in', 3), ('a', 2), ('art', 2), ('museum', 2)]" + ] + }, + "execution_count": 70, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим пустой словарь для мешка слов bow\n", + "bow_1: dict[str, int] = {}\n", + "\n", + "# пройдемся по словам текста\n", + "for word in words:\n", + "\n", + " # если нам встретилось слово, которое уже есть в словаре\n", + " if word in bow_1:\n", + "\n", + " # увеличим его значение (частоту) на 1\n", + " bow_1[word] = bow_1[word] + 1\n", + "\n", + " # в противном случае, если слово встречается впервые\n", + " else:\n", + "\n", + " # зададим ему значение 1\n", + " bow_1[word] = 1\n", + "\n", + "# отсортируем словарь по значению в убываюем порядке (reverse = True)\n", + "# и выведем шесть наиболее частотных слов\n", + "print(sorted(bow_1.items(), key=lambda item: item[1], reverse=True)[:6])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DckCYLgvaF3D" + }, + "source": [ + "##### Способ 2. Метод .get()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "-cfKJK7dUx6E", + "outputId": "01b035d5-f1cb-4e1d-d455-d6175a15b9c3" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[('the', 4), ('we', 3), ('in', 3), ('a', 2), ('art', 2), ('museum', 2)]" + ] + }, + "execution_count": 71, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bow_2: dict[str, int] = {}\n", + "\n", + "# снова пройдемся в цикле по словам\n", + "for word in words:\n", + "\n", + " # если слова еще нет в словаре, .get() выведет значение 0,\n", + " # к которому мы прибавим единицу\n", + " # если слово есть, метод .get() выведет существующее значение,\n", + " # например, 2 или 3,\n", + " # и мы также увеличим счетчик на 1\n", + " bow_2[word] = bow_2.get(word, 0) + 1\n", + "\n", + "# выведем наиболее популярные слова\n", + "print(sorted(bow_2.items(), key=lambda item: item[1], reverse=True)[:6])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "p9pnHw9JdTDb" + }, + "source": [ + "##### Способ 3. Модуль collections" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DBxI0C6GMO-P", + "outputId": "b688998c-0316-40a1-a3eb-38839afd60fd" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[('the', 4), ('we', 3), ('in', 3), ('a', 2), ('art', 2), ('museum', 2)]" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим объект этого класса, передав ему список слов\n", + "bow_3 = Counter(words)\n", + "\n", + "# выведем шесть наиболее часто встречающихся слов с помощью метода .most_common()\n", + "bow_3.most_common(6)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Encet8AUTxaK" + }, + "source": [ + "### Дополнительные материалы" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "PMf-4k76T17z" + }, + "source": [ + "#### Изменяемые и неизменяемые типы данных" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YSZEqdoqZPFJ" + }, + "source": [ + "Неизменяемый тип данных" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "evIywP2QteRj", + "outputId": "41dc2190-2e36-4393-d42d-594a8c8c0a86" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(9739968, str, 'Python')" + ] + }, + "execution_count": 73, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим строковый объект\n", + "string = \"Python\"\n", + "\n", + "# посмотрим на identity, type и value\n", + "# функция id() выводит адрес объекта в памяти компьютера\n", + "print(id(string), type(string), string)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ddda36SbVNP3", + "outputId": "1efe542a-2076-48b7-d8ff-f38f526ca50f" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(132833144673840, str, 'Python is cool')" + ] + }, + "execution_count": 74, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# попробуем изменить этот объект\n", + "string = string + \" is cool\"\n", + "\n", + "# посмотрим на identity, type и value\n", + "print(id(string), type(string), string)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zD5pA-shZS9y" + }, + "source": [ + "Изменяемый тип данных" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "m3v7sz66WaG2", + "outputId": "79bed439-00cc-4d22-ff23-ea2ac933869b" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(132833144305664, list, [1, 2, 3])" + ] + }, + "execution_count": 75, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим список\n", + "lst: list[int] = [1, 2, 3]\n", + "\n", + "# посмотрим на identity, type и value\n", + "print(id(lst), type(lst), lst)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "MwsfBPKuY44t", + "outputId": "e68fe4a2-9de8-4649-aab7-284c6868c3df" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(132833144305664, list, [1, 2, 3, 4])" + ] + }, + "execution_count": 76, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# добавим элемент в список\n", + "lst.append(4)\n", + "\n", + "# снова выведем identity, type и value\n", + "print(id(lst), type(lst), lst)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RN5eo53UcJ8v" + }, + "source": [ + "Копирование объектов" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "WHkQSdiHe7z6", + "outputId": "3214f311-d3a7-4f47-b029-413b6f76729c" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "('Python', 'Python is cool')" + ] + }, + "execution_count": 77, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вновь создадим строку\n", + "string = \"Python\"\n", + "\n", + "# скопируем через присваивание\n", + "string2 = string\n", + "\n", + "# изменим копию\n", + "string2 = string2 + \" is cool\"\n", + "\n", + "# посмотрим на результат\n", + "print(string, string2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "4acHz97ajcSH", + "outputId": "4cff9e9d-be08-41b3-9a3d-6883e02d0a71" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(False, False)" + ] + }, + "execution_count": 78, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# оператор == сравнивает значения (values)\n", + "# оператор is сравнивает identities\n", + "print(string == string2, string is string2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "LHQ7dLSjbLiF", + "outputId": "d24c9d3f-af32-4d65-9219-7336ad8b5cae" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([1, 2, 3, 4], [1, 2, 3, 4])" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# создадим список\n", + "lst = [1, 2, 3]\n", + "\n", + "# скопируем его в новую переменную через присваивание\n", + "lst2 = lst\n", + "\n", + "# добавим новый элемент в скопированный список\n", + "lst2.append(4)\n", + "\n", + "# выведем исходный список и копию\n", + "print(lst, lst2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Oje2eXOYjQwq", + "outputId": "750ce99e-09f8-42a1-f584-da308d4a4b51" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(True, True)" + ] + }, + "execution_count": 80, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# убедимся, что речь идет об одном и том же объекте\n", + "print(lst == lst2, lst is lst2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "bMxYXjZ1fwwV", + "outputId": "a4da24b7-1247-4586-a96f-b461ad1f9d47" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([1, 2, 3], [1, 2, 3, 4])" + ] + }, + "execution_count": 81, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# вновь создадим список\n", + "lst = [1, 2, 3]\n", + "\n", + "# скопируем с помощью метода .copy()\n", + "lst2 = lst.copy()\n", + "\n", + "# добавим новый элемент в скопированный список\n", + "lst2.append(4)\n", + "\n", + "# выведем исходный список и копию\n", + "print(lst, lst2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uajQvKK5gN2x", + "outputId": "17e77160-2826-4cdf-9328-06c7844b6dfd" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "([1, 2, 3, 4], [1, 2, 3, 4], True, False)" + ] + }, + "execution_count": 82, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# теперь сделаем значения списков одинаковыми\n", + "lst.append(4)\n", + "\n", + "# и убедимся, что это по-прежнему разные объекты\n", + "print(lst, lst2, lst == lst2, lst is lst2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Etf2OVxIsK7R" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/python/makarov/chapter_9_dictionaries.py b/python/makarov/chapter_9_dictionaries.py new file mode 100644 index 00000000..e767219c --- /dev/null +++ b/python/makarov/chapter_9_dictionaries.py @@ -0,0 +1,609 @@ +"""Макаров. + +Словарь в Питоне +""" + +# ## Словарь в Питоне + +# ### Понятие словаря + +# #### Создание словаря + +# + +# пустой словарь можно создать с помощью {} или функции dict() +# импортируем класс Counter +from collections import Counter + +# импортируем функцию pprint() из модуля pprint +# некоторые структуры данных она выводит лучше, чем обычная print() +from pprint import pprint + +import numpy as np + +dict_1: dict[str, str] = {} +dict_2: dict[str, str] = dict() # pylint: disable=R1735 +print(dict_1, dict_2) +# - + +# словарь можно сразу заполнить ключами и значениями +company: dict[str, str | int] = { + "name": "Toyota", + "founded": 1937, + "founder": "Kiichiro Toyoda", +} +company + +# словарь можно создать из вложенных списков +tickers: dict[str, str] = dict([["TYO", "Toyota"], ["TSLA", "Tesla"], ["F", "Ford"]]) +tickers + +# + +# если поместить ключи в кортеж +keys: tuple[str, ...] = ("k1", "k2", "k3") +# и задать значение +value_global = 0 + +# то с помощью метода .fromkeys() можно создать словарь +# с этими ключами и заданным значением для каждого из них +empty_values = dict.fromkeys(keys, value_global) +empty_values +# - + +# #### Ключи и значения словаря + +# Виды значений словаря + +# + +# приведем пример того, какими могут быть значения словаря +value_types: dict[str, int | str | bool | None | list[int] | object | float] = { + "k1": 123, + "k2": "string", + "k3": np.nan, # тип "Пропущенное значение" + "k4": True, # логическое значение + "k5": None, + "k6": [1, 2, 3], + "k7": np.array([1, 2, 3]), + "k8": {1: "v1", 2: "v2", 3: "v3"}, +} + +value_types +# - + +# Методы .keys(), .values() и .items() + +# создадим несложный словарь с информацией о сотруднике +person: dict[str, str | int | list[str]] = { + "first name": "Иван", + "last name": "Иванов", + "born": 1980, + "dept": "IT", +} + +# посмотрим на ключи и +print(person.keys()) + +# значения +print(person.values()) + +# а также на пары ключ-значение в виде списка из кортежей +print(person.items()) + +# Использование цикла for + +# ключи и значения можно вывести в цикле for +for key, value_p in person.items(): + print(key, value_p) + +# Доступ по ключу и метод .get() + +# значение можно посмотреть по ключу +person["last name"] + +# + +# если такого ключа нет, Питон выдаст ошибку +# person['education'] --> Error +# - + +# чтобы этого не произошло, можно использовать метод .get() +# по умолчанию при отсутствии ключа он выводит значение None +print(person.get("education")) + +# если ключ все-таки есть, .get() выведет соответствующее значение +print(person.get("born")) + +# Проверка вхождения ключа и значения в словарь + +# проверим есть ли такой ключ +print("born" in person) + +# и такое значение +print(1980 in person.values()) + +# можно также проверить наличие и ключа, и значения одновременно +print(("born", 1980) in person.items()) + +# ### Операции со словарями + +# #### Добавление и изменение элементов + +# добавить элемент можно, передав новому ключу новое значение +# обратите внимание, в данном случае новое значение - это список +person["languages"] = ["Python", "C++"] +person + +# изменить элемент можно, передав существующему ключу новое значение, +# значение - это по-прежнему список, но из одного элемента +person["languages"] = ["Python"] +person + +# + +# возьмем еще один словарь +new_elements: dict[str, str | int] = {"job": "программист", "experience": 7} + +# и присоединим его к существующему словарю с помощью метода .update() +person.update(new_elements) +person +# - + +# метод .setdefault() проверит есть ли ключ в словаре, +# если "да", значение не изменится +person.setdefault("last name", "Петров") +person + +# если нет, будет добавлен новый ключ и соответствующее значение +person.setdefault("f_languages", ["русский", "английский"]) +person + +# #### Удаление элементов + +# метод .pop() удаляет элемент по ключу и выводит удаляемое значение +print(person.pop("dept")) + +# мы видим, что пары 'dept' : 'IT' больше нет +person + +# ключевое слово del также удаляет элемент по ключу +# удаляемое значение не выводится +del person["born"] + +# метод .popitem() удаляет последний добавленный элемент и выводит его +person.popitem() + +# метод .clear() удаляет все элементы словаря +person.clear() +person + +# ключевое слово del также позволяет удалить словарь целиком +del person + +# убедимся, что такого словаря больше нет +person + +# #### Сортировка словарей + +# возьмем несложный словарь +dict_to_sort: dict[str, int] = {"k2": 30, "k1": 20, "k3": 10} + +# отсортируем ключи +sorted(dict_to_sort) + +# и значения +sorted(dict_to_sort.values()) + +# посмотрим на пары ключ : значение +dict_to_sort.items() + +# для их сортировки по ключу (индекс [0]) +# воспользуемся методом .items() и lambda-функцией +sorted(dict_to_sort.items(), key=lambda item: item[0]) + +# сортировка по значению выполняется так же, однако +# lambda-функции мы передаем индекс [1] +sorted(dict_to_sort.items(), key=lambda item: item[1]) + +# #### Копирование словарей + +# создадим исходный словарь с количеством студентов на первом и втором курсах университета +original: dict[str, int] = {"Первый курс": 174, "Второй курс": 131} + +# Копирование с помощью метода .copy() + +# + +# создадим копию этого словаря с помощью метода .copy() +new_1 = original.copy() + +# добавим информацию о третьем курсе в новый словарь +new_1["Третий курс"] = 117 + +# исходный словарь не изменился +print(original) +print(new_1) +# - + +# Копирование через оператор присваивания `=` (так делать не стоит!) + +# + +# передадим исходный словарь в новую переменную +new_2 = original + +# удалим элементы нового словаря +new_2.clear() + +# из исходного словаря данные также удалились +print(original) +print(new_2) +# - + +# ### Функция `dir()` + +# + +# функция dir() возвращает все методы передаваемого ей объекта +some_dict = {"k": 1} + +# вначале идут специальные методы, +# они начинаются и заканчиваются символом '__' +# выведем первые 11 элементов +print(dir(some_dict)[:11]) +# - + +# когда мы передаем наш словарь функции print(), +print(some_dict) + +# на самом деле мы применяем к объекту метод .__str__() +some_dict.__str__() # pylint: disable=C2801 + +# + +# в большинстве случаев нас будут интересовать методы без '__' +methods = dir(some_dict)[-11:] + +print(methods) +# - + +# ### Dict comprehension + +# создадим еще один несложный словарь +source_dict: dict[str, int] = {"k1": 2, "k2": 4, "k3": 6} + +# с помощью dict comprehension умножим каждое значение на два +new_source_dict = {key: value * 2 for (key, value) in source_dict.items()} + +# сделаем символы всех ключей заглавными +new_source_dict = {key.upper(): value for (key, value) in source_dict.items()} + +# + +# добавим условие, что значение должно быть больше двух И меньше шести +new_dict_1 = { + key: value for (key, value) in source_dict.items() if value > 2 if value < 6 +} + +print(new_dict_1) + +# + +new_dict: dict[str, int] = {} + +# при решении этой же задачи в цикле for +for key, value in source_dict.items(): + + # мы бы использовали логическое И (and) + if 2 < value < 6: + + # если условия верны, записываем ключ и значение в новый словарь + new_dict[key] = value + +new_dict +# - + +# условие с if-else ставится в самом начале схемы dict comprehension +# заменим значение на слово even, если оно четное, и odd, если нечетное +even_odd_dict: dict[str, str] = { + key: ("even" if value % 2 == 0 else "odd") for (key, value) in source_dict.items() +} + +# + +# dict comprehension можно использовать вместо метода .fromkeys() +keys = ("k1", "k2", "k3") + +# передадим словарю ключи из кортежа keys и зададим значение 0 каждому из них +zeros_dict = {key: 0 for key in keys} +# - + +# ### Дополнительные примеры + +# #### lambda-функции, функции `map()` и `zip()` + +# Пример со списком + +# возьмем список слов +words: list[str] = ["apple", "banana", "fig", "blackberry"] + +# создадим lambda-функцию, которая посчитает длину передаваемого ей слова +# с помощью функции map() применим lambda-функцию +# к каждому элементу списка words +# и поместим длины слов в новый список length с помощью функции list() +length = list(map(len, words)) +length + +# с помощью функции zip() поэлементно соединим оба списка и +# преобразуем в словарь +from_zip_dict = dict(zip(words, length)) + +# то же самое можно сделать с помощью функции zip() и list comprehension +zip_length_dict = dict(zip(words, [len(word) for word in words])) + +# Пример со словарем + +# возьмем словарь с ростом людей в футах +height_feet: dict[str, float] = {"Alex": 6.1, "Jerry": 5.4, "Ben": 5.8} + +# для преобразования футов в метры создадим lambda-функцию lambda m: m * 0.3048 +# применим эту функцию к значениям словаря с помощью функции map() +# преобразуем в список +metres = list(map(lambda m: m * 0.3048, height_feet.values())) +metres + +# с помощью функции zip() соединим ключи исходного словаря с элементами списка metres +dict(zip(height_feet.keys(), np.round(metres, 2))) + +# то же самое можно выполнить с помощью dict comprehensions +# всего в одну строчку +# мы просто преобразуем значения словаря в метры +students_heights_dict = { + key: np.round(value * 0.3048, 2) for (key, value) in height_feet.items() +} + +# #### Вложенные словари + +# возьмем словарь, ключами которого будут id сотрудников +employees: dict[str, dict[str, str | int | float]] = { + "id1": { + "first name": "Александр", + "last name": "Иванов", + "age": 30, + "job": "программист", + }, + "id2": { + "first name": "Ольга", + "last name": "Петрова", + "age": 35, + "job": "ML-engineer", + }, +} + +# а значениями - вложенные словари с информацией о них +for value_e in employees.values(): + print(value_e) + +# ##### Базовый операции + +# для того чтобы вывести значение элемента вложенного словаря, +# воспользуемся двойным ключом +print(employees["id1"]["age"]) + +# + +# добавим информацию о новом сотруднике +employees["id3"] = { + "first name": "Дарья", + "last name": "Некрасова", + "age": 27, + "job": "веб-дизайнер", +} + +# и выведем обновленный словарь с помощью функции pprint() +pprint(employees) +# - + +# изменить значение вложенного словаря можно также с помощью двойного ключа +employees["id3"]["age"] = 26 +pprint(employees) + +# ##### Циклы `for` + +# + +# заменим тип данных в информации о возрасте с int на float + +# для этого вначале пройдемся по вложенным словарям, +# т.е. по значениям info внешнего словаря employees +for info in employees.values(): + + # затем по ключам и значениям вложенного словаря info + for key_info, value_info in info.items(): + + # если ключ совпадет со словом 'age' + if key_info == "age": + + # преобразуем значение в тип float + info[key_info] = float(value_info) + +pprint(employees) +# - + +# ##### Вложенные словари и dict comprehension + +# преоразуем обратно из float в int, но уже через dict comprehension +# для начала просто выведем словарь employees без изменений +pprint({id: info for id, info in employees.items()}) + +# а затем заменим значение внешнего словаря info (т.е. вложенный словарь) +# на еще один dict comprehension с условием if-else +pprint( + { + id: { + key: (int(value_i) if key == "age" else value_i) + for key, value_i in info.items() + } + for id, info in employees.items() + } +) + +# #### Частота слов в тексте + +# возьмем знакомый нам текст +corpus = ( + "When we were in Paris we visited a lot of museums. " + "We first went to the Louvre, the largest art museum in the world." + "I have always been interested in art so I spent many hours there. " + "The museum is enormous, so a week there would not be enough." +) + +# ##### Предварительная обработка текста + +# разделим его на слова +words = corpus.split() +print(words) + +# с помощью list comprehension удалим точки, запятые +# и переведем все слова в нижний регистр +words = [word.strip(".").strip(",").lower() for word in words] +print(words) + +# ##### Способ 1. Условие if-else + +# + +# создадим пустой словарь для мешка слов bow +bow_1: dict[str, int] = {} + +# пройдемся по словам текста +for word in words: + + # если нам встретилось слово, которое уже есть в словаре + if word in bow_1: + + # увеличим его значение (частоту) на 1 + bow_1[word] = bow_1[word] + 1 + + # в противном случае, если слово встречается впервые + else: + + # зададим ему значение 1 + bow_1[word] = 1 + +# отсортируем словарь по значению в убываюем порядке (reverse = True) +# и выведем шесть наиболее частотных слов +print(sorted(bow_1.items(), key=lambda item: item[1], reverse=True)[:6]) +# - + +# ##### Способ 2. Метод .get() + +# + +bow_2: dict[str, int] = {} + +# снова пройдемся в цикле по словам +for word in words: + + # если слова еще нет в словаре, .get() выведет значение 0, + # к которому мы прибавим единицу + # если слово есть, метод .get() выведет существующее значение, + # например, 2 или 3, + # и мы также увеличим счетчик на 1 + bow_2[word] = bow_2.get(word, 0) + 1 + +# выведем наиболее популярные слова +print(sorted(bow_2.items(), key=lambda item: item[1], reverse=True)[:6]) +# - + +# ##### Способ 3. Модуль collections + +# + +# создадим объект этого класса, передав ему список слов +bow_3 = Counter(words) + +# выведем шесть наиболее часто встречающихся слов с помощью метода .most_common() +bow_3.most_common(6) +# - + +# ### Дополнительные материалы + +# #### Изменяемые и неизменяемые типы данных + +# Неизменяемый тип данных + +# + +# создадим строковый объект +string = "Python" + +# посмотрим на identity, type и value +# функция id() выводит адрес объекта в памяти компьютера +print(id(string), type(string), string) + +# + +# попробуем изменить этот объект +string = string + " is cool" + +# посмотрим на identity, type и value +print(id(string), type(string), string) +# - + +# Изменяемый тип данных + +# + +# создадим список +lst: list[int] = [1, 2, 3] + +# посмотрим на identity, type и value +print(id(lst), type(lst), lst) + +# + +# добавим элемент в список +lst.append(4) + +# снова выведем identity, type и value +print(id(lst), type(lst), lst) +# - + +# Копирование объектов + +# + +# вновь создадим строку +string = "Python" + +# скопируем через присваивание +string2 = string + +# изменим копию +string2 = string2 + " is cool" + +# посмотрим на результат +print(string, string2) +# - + +# оператор == сравнивает значения (values) +# оператор is сравнивает identities +print(string == string2, string is string2) + +# + +# создадим список +lst = [1, 2, 3] + +# скопируем его в новую переменную через присваивание +lst2 = lst + +# добавим новый элемент в скопированный список +lst2.append(4) + +# выведем исходный список и копию +print(lst, lst2) +# - + +# убедимся, что речь идет об одном и том же объекте +print(lst == lst2, lst is lst2) + +# + +# вновь создадим список +lst = [1, 2, 3] + +# скопируем с помощью метода .copy() +lst2 = lst.copy() + +# добавим новый элемент в скопированный список +lst2.append(4) + +# выведем исходный список и копию +print(lst, lst2) + +# + +# теперь сделаем значения списков одинаковыми +lst.append(4) + +# и убедимся, что это по-прежнему разные объекты +print(lst, lst2, lst == lst2, lst is lst2) +# - diff --git a/python/oop.ipynb b/python/oop.ipynb new file mode 100644 index 00000000..182dbc20 --- /dev/null +++ b/python/oop.ipynb @@ -0,0 +1,404 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "id": "efee80ea", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'OOP Молчанов.'" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\"\"\"OOP Молчанов.\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "b3e4e468", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hasan \n", + "\n", + "Person\n" + ] + }, + { + "data": { + "text/plain": [ + "['__class__',\n", + " '__delattr__',\n", + " '__dict__',\n", + " '__dir__',\n", + " '__doc__',\n", + " '__eq__',\n", + " '__firstlineno__',\n", + " '__format__',\n", + " '__ge__',\n", + " '__getattribute__',\n", + " '__getstate__',\n", + " '__gt__',\n", + " '__hash__',\n", + " '__init__',\n", + " '__init_subclass__',\n", + " '__le__',\n", + " '__lt__',\n", + " '__module__',\n", + " '__ne__',\n", + " '__new__',\n", + " '__reduce__',\n", + " '__reduce_ex__',\n", + " '__repr__',\n", + " '__setattr__',\n", + " '__sizeof__',\n", + " '__static_attributes__',\n", + " '__str__',\n", + " '__subclasshook__',\n", + " '__weakref__',\n", + " 'name']" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 1 урок\n", + "\n", + "\n", + "class Person:\n", + " name = \"Hasan\"\n", + "\n", + "\n", + "print(Person.name, \"\\n\")\n", + "print(Person.__name__)\n", + "\n", + "dir(Person)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e2370139", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \n", + "\n", + " \n", + "\n", + "Person\n" + ] + }, + { + "data": { + "text/plain": [ + "'Hasan'" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "print(Person.__class__, \"\\n\")\n", + "\n", + "p = Person() # создаём экземпляр класса\n", + "\n", + "print(p.__class__, \"\\n\")\n", + "print(p.__class__.__name__)\n", + "\n", + "type(p)\n", + "\n", + "new_person = type(p)() # создание экземпляра класса таким методом\n", + "new_person.name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ec125fc0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "mappingproxy({'__module__': '__main__',\n", + " '__firstlineno__': 3,\n", + " 'name': 'Hasan',\n", + " '__static_attributes__': (),\n", + " '__dict__': ,\n", + " '__weakref__': ,\n", + " '__doc__': None,\n", + " 'age': 18})" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 2 урок\n", + "Person.age = 18 # Обращение к полю класса и записывание значения\n", + "\n", + "Person.__dict__ # выводит все поля класса\n", + "\n", + "getattr(Person, \"name\") # получаем поле класса\n", + "setattr(Person, \"DoB\", \"10.19.2000\") # устанавливаем, можно переопределять\n", + "delattr(Person, \"DoB\") # удаляем\n", + "\n", + "Person.__dict__" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "21b2554c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "mappingproxy({'__module__': '__main__',\n", + " '__firstlineno__': 1,\n", + " 'name': 'Hasan',\n", + " 'hello': ,\n", + " '__static_attributes__': (),\n", + " '__dict__': ,\n", + " '__weakref__': ,\n", + " '__doc__': None})" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "class Person:\n", + " name = \"Hasan\"\n", + "\n", + " def hello():\n", + " print(\"Hello world\")\n", + "\n", + "\n", + "# Person.hello()\n", + "\n", + "\n", + "Person.__dict__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a2f892a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'__module__': '__main__', '__firstlineno__': 1, 'name': 'Hasan', 'hello': , '__static_attributes__': (), '__dict__': , '__weakref__': , '__doc__': None}\n", + "<__main__.Person object at 0x000001C8D0CB25F0>\n", + "<__main__.Person object at 0x000001C8D0CB25F0>\n", + "id p1 1962008061424 and id p2 1962008067472\n", + "dict p1 {'name': 'Ismail', 'age': 123} and dict p2 {'name': 'Abubakr'}\n" + ] + }, + { + "ename": "AttributeError", + "evalue": "'Person' object has no attribute 'age'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[21], line 26\u001b[0m\n\u001b[0;32m 22\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdict p1 \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mp1\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__dict__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m and dict p2 \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mp2\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__dict__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 24\u001b[0m \u001b[38;5;66;03m# В самом class Person поля не будут изменены\u001b[39;00m\n\u001b[1;32m---> 26\u001b[0m p2\u001b[38;5;241m.\u001b[39mage\n", + "\u001b[1;31mAttributeError\u001b[0m: 'Person' object has no attribute 'age'" + ] + } + ], + "source": [ + "# 3 урок\n", + "# Классы - это callable объекты, после объявления\n", + "# python автоматически присваивает ему некоторые свойства\n", + "\n", + "print(Person.__dict__)\n", + "\n", + "p1 = Person()\n", + "print(p1)\n", + "\n", + "p2 = Person()\n", + "print(p1)\n", + "\n", + "print(f\"id p1 {id(p1)} and id p2 {id(p2)}\")\n", + "# p1.name == p2.name\n", + "# и id их будут равны так как ссылаются они на одно поле одного объекта\n", + "\n", + "\n", + "p1.name = \"Ismail\"\n", + "p2.name = \"Abubakr\"\n", + "p1.age = 123\n", + "\n", + "print(f\"dict p1 {p1.__dict__} and dict p2 {p2.__dict__}\")\n", + "\n", + "# В самом class Person поля не будут изменены\n", + "\n", + "# p2.age ERROR" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70a22908", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__type_params__']\n", + "['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']\n" + ] + } + ], + "source": [ + "# 4 урок\n", + "\n", + "\n", + "class Person:\n", + " def hello():\n", + " print(\"Hello!\")\n", + "\n", + "\n", + "print(Person.hello)\n", + "\n", + "p1 = Person()\n", + "\n", + "# p.hello\n", + "\n", + "print(type(p1.hello))\n", + "print(type(Person.hello))\n", + "\n", + "\n", + "print(dir(Person.hello))\n", + "print(dir(p1.hello))\n", + "\n", + "\n", + "class Person2:\n", + " def hello(self):\n", + " print(self)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "07721cb1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'name': 'Hasan'}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# 5 урок метод __init__\n", + "\n", + "\n", + "class Person22:\n", + " def __init__(self, name):\n", + " self.name = name\n", + "\n", + " def display(self):\n", + " print(self.name)\n", + "\n", + " # end def\n", + "\n", + "\n", + "p2p = Person22(\"Hasan\")\n", + "p2p.__dict__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "148e1153", + "metadata": {}, + "outputs": [], + "source": [ + "# 6 урок метод декораторы\n", + "\n", + "\n", + "class Personn:\n", + " def hello(self):\n", + " print(\"Hello\")\n", + "\n", + " @staticmethod\n", + " def goodbye():\n", + " print(\"Goodbye\")\n", + "\n", + "\n", + "aa = Personn()\n", + "bb = Personn()\n", + "\n", + "# При вызове метода goodbye, айдишники объектов будут одинаковы, потому что\n", + "# они ссылаются на один объект класса\n", + "\n", + "# Статические методы не имеют доступа к свойствам и методам экземпляров\n", + "# классов, это просто функция, не принимающая аргументов\n", + "\n", + "# Они нужны для того, чтобы ,к примеру, объединить несколько функций в\n", + "# один объект, можно эти функции выносить за классы, используются как\n", + "# вспомогательные методы" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/python/oop.py b/python/oop.py new file mode 100644 index 00000000..9994bde2 --- /dev/null +++ b/python/oop.py @@ -0,0 +1,143 @@ +"""OOP Молчанов.""" + + +# + +# 1 урок + +class Person: + name = 'Hasan' + +print(Person.name,'\n') +print(Person.__name__) + +dir(Person) + +# + +print(Person.__class__,'\n') + +p = Person() # создаём экземпляр класса + +print(p.__class__,'\n') +print(p.__class__.__name__) + +type(p) + +new_person = type(p)() # создание экземпляра класса таким методом +new_person.name + +# + +# 2 урок +Person.age = 18 # Обращение к полю класса и записывание значения + +Person.__dict__ # выводит все поля класса + +getattr(Person, 'name') # получаем поле класса +setattr(Person, 'DoB','10.19.2000') # устанавливаем, можно переопределять +delattr(Person, 'DoB') # удаляем + +Person.__dict__ + + +# + +class Person: + name = "Hasan" + + def hello(): + print("Hello world") + +# Person.hello() + +Person.__dict__ + +# + +# 3 урок +# Классы - это callable объекты, после объявления +# python автоматически присваивает ему некоторые свойства + +print(Person.__dict__) + +p1 = Person() +print(p1) + +p2 = Person() +print(p1) + +print(f"id p1 {id(p1)} and id p2 {id(p2)}") +# p1.name == p2.name +# и id их будут равны так как ссылаются они на одно поле одного объекта + + +p1.name = "Ismail" +p2.name = "Abubakr" +p1.age = 123 + +print(f"dict p1 {p1.__dict__} and dict p2 {p2.__dict__}") + +# В самом class Person поля не будут изменены + +# p2.age ERROR + +# + +# 4 урок + +class Person: + def hello(): + print("Hello!") + +print(Person.hello) + +p1 = Person() + +# p.hello + +print(type(p1.hello)) +print(type(Person.hello)) + + +print(dir(Person.hello)) +print(dir(p1.hello)) + +class Person2: + def hello(self): + print(self) + + + +# + +# 5 урок метод __init__ + +class Person22: + def __init__(self,name): + self.name = name + + def display(self): + print(self.name) + # end def + +p2p = Person22('Hasan') +p2p.__dict__ + + +# + +# 6 урок метод декораторы + +class Personn: + def hello(self): + print('Hello') + + @staticmethod + def goodbye(): + print('Goodbye') + +aa = Personn() +bb = Personn() + +# При вызове метода goodbye, айдишники объектов будут одинаковы, потому что +# они ссылаются на один объект класса + +# Статические методы не имеют доступа к свойствам и методам экземпляров +# классов, это просто функция, не принимающая аргументов + +# Они нужны для того, чтобы ,к примеру, объединить несколько функций в +# один объект, можно эти функции выносить за классы, используются как +# вспомогательные методы From 4d808b08a4379c36dda3c3f4fc947f4fccea90cd Mon Sep 17 00:00:00 2001 From: hasan613 Date: Wed, 29 Apr 2026 23:13:27 +0300 Subject: [PATCH 2/2] fix: correct imports --- python/makarov/chapter_15_iterators.ipynb | 3 +-- python/makarov/chapter_15_iterators.py | 17 ++++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/python/makarov/chapter_15_iterators.ipynb b/python/makarov/chapter_15_iterators.ipynb index 1ca189f9..471fbc40 100644 --- a/python/makarov/chapter_15_iterators.ipynb +++ b/python/makarov/chapter_15_iterators.ipynb @@ -61,9 +61,8 @@ } ], "source": [ - "from collections.abc import Iterator\n", + "from collections.abc import Generator, Iterator\n", "from itertools import chain, count, cycle\n", - "from typing import Generator\n", "\n", "for index in [1, 2, 3]:\n", " print(index)" diff --git a/python/makarov/chapter_15_iterators.py b/python/makarov/chapter_15_iterators.py index 853f52c7..cf33df01 100644 --- a/python/makarov/chapter_15_iterators.py +++ b/python/makarov/chapter_15_iterators.py @@ -10,9 +10,8 @@ # #### Основные определения # + -from collections.abc import Iterator +from collections.abc import Generator, Iterator from itertools import chain, count, cycle -from typing import Generator for index in [1, 2, 3]: print(index) @@ -47,7 +46,7 @@ print(f"B: {next(iterator_b)}") # - -iterable_object +# iterable_object # + # print(f'A: {next(iterator_a)}') @@ -89,7 +88,8 @@ # Возведение в квадрат class Square: - """Итератор, возводящий в квадрат числа из переданной последовательности.""" + """Итератор, возводящий в квадрат числа из переданной + последовательности.""" def __init__(self, seq: list[int]) -> None: """Инициализация итератора.""" @@ -120,7 +120,8 @@ def __next__(self) -> int: # Счетчик class Counter: - """Итератор, генерирующий последовательность целых чисел в заданном диапазоне.""" + """Итератор, генерирующий последовательность целых чисел + в заданном диапазоне.""" def __init__(self, start: int = 3, stop: int = 9) -> None: """Инициализирует итератор с заданными границами диапазона.""" @@ -304,8 +305,8 @@ def quadratic_poly(num_arg: int) -> int: break # + -string = "Python" -iterator_e = cycle(string) +stringg = "Python" +iterator_e = cycle(stringg) limit = 10 for item_3 in iterator_e: @@ -325,5 +326,3 @@ def quadratic_poly(num_arg: int) -> int: print(list(chain.from_iterable(["abc", "def"]))) result_1 = sum(chain.from_iterable([[1, 2, 3], [4, 5, 6], [7, 8, 9]])) - -