├── .pylintrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── libraries.md └── python_pd ├── 01_intro ├── 00_overview.md ├── 01_introduction.md ├── 02_installation.md └── image │ ├── download_mac_1.png │ ├── download_mac_2.png │ ├── download_mac_3.png │ ├── download_windows.png │ └── installation.png ├── 02_syntax ├── 00_overview.md ├── 01_simple_types.ipynb ├── 02_variables.ipynb ├── 03_control_structures.ipynb ├── 04_functions.ipynb ├── 05_dtyping.ipynb └── image │ ├── multiple_names.png │ ├── multiple_object.png │ ├── name_object.png │ └── pyobject_int.png ├── 03_collections ├── 00_overview.md ├── 01_im_mutable_and_copy.ipynb ├── 02_comprehensions.ipynb ├── 03_collections.ipynb ├── 04_iter.ipynb ├── 05_itertools.ipynb ├── basic_collections │ ├── 00_overview.md │ ├── 01_string.ipynb │ ├── 02_list.ipynb │ ├── 03_dict.ipynb │ ├── 04_tuple.ipynb │ ├── 05_set.ipynb │ └── 06_convert.ipynb └── image │ ├── array_shift.png │ ├── comprehensions.png │ ├── copy.png │ ├── copy_2.png │ ├── copy_3.png │ ├── deque.png │ ├── dict.png │ ├── dragon_curve.png │ ├── gen_iter.png │ ├── graph.png │ ├── immutable.png │ ├── index.png │ ├── prefix_suffix.png │ ├── stack.png │ ├── tuple.png │ └── tuple_2.png ├── 04_functions ├── 00_overview.md ├── 01_args.ipynb ├── 02_return.ipynb ├── 03_lambda.ipynb ├── 04_legb.ipynb ├── 05_recursion.ipynb ├── 06_closures.ipynb ├── 07_decorators.ipynb ├── 08_generators.ipynb ├── 09_functools.ipynb ├── 10_exceptions.ipynb └── image │ ├── dv.png │ ├── enclosing.png │ ├── fib_graph.png │ └── legb.png ├── 05_files ├── 00_overview.md ├── 01_files.ipynb ├── 02_io.ipynb ├── 03_cmanagers.ipynb ├── 04_json.ipynb ├── 05_csv.ipynb ├── 06_pickle.ipynb ├── 07_os_path.ipynb ├── 08_pathlib.ipynb ├── data.csv ├── data.txt ├── image │ └── mode.png └── write_data.txt ├── 06_classes ├── 00_overview.md ├── 01_class.ipynb ├── 02_attr.ipynb ├── 03_methods.ipynb ├── 04_inheritance.ipynb ├── 05_magic.ipynb ├── 06_protocols.ipynb ├── 07_duck_typing.ipynb ├── 08_property.ipynb ├── 09_decorators.ipynb ├── 10_abc.ipynb ├── 11_meta.ipynb └── image │ ├── attr_cls.png │ ├── attr_self.png │ ├── diamond_inh.png │ ├── diamond_inh_object.png │ ├── inh_graph.png │ ├── inh_graph_2.png │ └── inh_graph_3.png ├── 07_import ├── 00_overview.md ├── 01_modules.ipynb ├── 02_types_imports.ipynb ├── 03_system.ipynb ├── 04_search.ipynb ├── 05_pip.ipynb ├── 06_venv.ipynb └── 07_pypi.ipynb ├── badcode.ipynb ├── best_hello_world.py └── work └── syntax ├── README.md └── fizzbuzz ├── README.md ├── fizzbuzz.py ├── solution.py ├── test_fizzbuzz.py └── test_solution.py /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Кодекс поведения 2 | 3 | ## Обязательства 4 | 5 | В интересах создания открытого и дружелюбного сообщества, мы, как авторы и участники, обязуемся сделать участие в проекте и сообществе без притеснений независимо от возраста, телосложения, наличия инвалидности, этнической принадлежности, половой или сексуальной идентичности и выражения, уровня опыта, национальности, внешности или расы, вероисповедания, политических или иных взглядов. 6 | 7 | ## Стандарты 8 | 9 | От всех членов комьюнити без исключения мы ожидаем следующего: 10 | 11 | - участвуйте, этим вы делаете свой вклад в укрепление сообщества; 12 | - использование дружелюбного тона и понятного языка; 13 | - уважение к чужой точке зрения и опыту; 14 | - корректное восприятие конструктивной критики; 15 | - ориентирование на то, что лучше подходит для сообщества; 16 | - проявление эмпатии к другим участникам проекта. 17 | 18 | Примеры неприемлемого поведения участников включают в себя: 19 | 20 | - использование выражений или изображений сексуального характера и нежелательное сексуальное внимание или домогательство; 21 | - троллинг, оскорбительные/уничижительные комментарии, переход на личности или затрагивание политических убеждений; 22 | - публичное или личное домогательство; 23 | - публикация личной информации других лиц, например, физического или электронного адреса, без явного разрешения; 24 | - иное поведение, которое обоснованно считать неуместным в профессиональной обстановке. 25 | 26 | ## Обязанности 27 | 28 | Участники, сопровождающие проект, отвечают за разъяснение стандартов приемлемого поведение и, как ожидается, принимают соответствующие и справедливые меры по исправлению положения при возникновении случаев неприемлемого поведения. 29 | 30 | Разработчики проекта вправе удалять, редактировать или отклонять комментарии, коммиты, код, изменения в вики, вопросы и другой вклад, который не совпадает с Кодексом Поведения, или забанить временно или бессрочно участника за поведение, которое расценено как нецелесообразное, угрожающее, оскорбительное или вредное. 31 | 32 | ## Область применения 33 | 34 | Этот Кодекс Поведения применим в рамках проекта и в общественных местах, когда человек представляет проект или сообщество. Примеры представления проекта или сообщества включают использование адреса электронной почты официального проекта, публикации в официальном аккаунте в социальных сетях, или упоминания как представителя в онлайн или оффлайн мероприятии. Варианты представления проекта могут быть дополнительно определены и уточнены автором проекта. 35 | 36 | ## Претензии 37 | 38 | О фактах нарушения или иных прецедентах неприемлемого поведения сообщайте команде проекта по электронной почте vvs.x00@gmail.com. Команда проекта рассматривает и изучает жалобы, и реагирует соответствующим образом, целесообразным при данных обстоятельствах. Команда проекта обязуется сохранять конфиденциальность в отношении автора обращения. Подробная информация о политике претензий может быть размещена отдельно. К участникам проекта, не руководствующимся или не соблюдающим Кодекс Поведения добровольно, могут быть применены временные или постоянные ограничения, определяемые руководителями проекта. 39 | 40 | ## Атрибуция 41 | 42 | Данный Кодекс Поведения основан на [Contributor Covenant][homepage], версия 1.4, 43 | доступна на https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 44 | 45 | [homepage]: https://www.contributor-covenant.org 46 | 47 | Ответы на распространенные вопросы об этом кодексе поведения смотрите на 48 | https://www.contributor-covenant.org/faq 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Коллективное участие в проекте 2 | 3 | ## Стиль 4 | 5 | В курсе используются следующие стандарт кодирования: 6 | 7 | - [PEP 8 - Стиль кодирования на Python](https://www.python.org/dev/peps/pep-0008/) 8 | - [PEP 257 - Соглашение о строках документации](https://www.python.org/dev/peps/pep-0257/) 9 | 10 | ## Сообщить об ошибке 11 | 12 | Если вы нашли ошибку не стесняйтесь сообщить об этом. 13 | 14 | Чтобы сообщить об ошибке придерживайтесь следующих простых правил: 15 | 16 | - Проверьте раздел ```issues```, чтобы не создавать дубликатов 17 | - Задайте понятный заголовок ```issues```, лаконично и исчерпывающе определяющий проблему 18 | - постарайтесь не допускать двойного смысла, сленга и т.д. 19 | - Опишите сценарий воспроизведения ошибки или место в тексте, где она присутствует 20 | - скриншоты очень сильно помогают, но не заменяют сценарий 21 | - добавьте сообщение об ошибке (если это связано с кодом) 22 | - Опишите в чем заключается ошибка по вашему мнению 23 | - Опишите ожидаемое поведение или представление 24 | 25 | ## Предложения по улучшению курса 26 | 27 | Авторы приветствуют предложения по улучшению курса. Вы можете предложить: 28 | - новую тему для включения в курс; 29 | - пример кода; 30 | - полезную ссылку на интернет источник/обсуждение; 31 | - задание для самостоятельного решения; 32 | - литературу; 33 | - библиотеку; 34 | - и другой полезный материал. 35 | 36 | Для внесения предложения по улучшению курса следуйте простым шагам: 37 | 38 | - Задайте понятный заголовок ```issue```, лаконично и исчерпывающе определяющий Ваше предложение. 39 | - Укажите, что вы предлагаете: новую тему, пример, задание, ссылку и др. 40 | - Опишите суть предложения и обсудите в ```issue``` варианты реализации (для примера или задания), содержание (для темы), предоставляемые возможности (для библиотеки) и т.д. 41 | - Реализуйте Ваше предложение и предложите его через Pull request. 42 | 43 | ## Добавление новых заданий 44 | 45 | Вы можете добавить не только новые темы, примеры и ссылки, но и интересные задания для самостоятельного выполнения студентами. Для этого придерживайтесь следующих шагов: 46 | 47 | - Выберите директорию в ```python_pd/work``` наиболее подходящую к тематике вашего задания. 48 | - Создайте новую директорию в выбранной папке с коротким, но информативным названием. 49 | - Разместите описание задания в файле ```README.md```. 50 | - При необходимости добавьте файл с входными данными с именем ```data``` и нужным расширением. 51 | - Разместите шаблон решения. 52 | - Добавьте набор тестов в файле с префиксом ```test_``` для проверки правильности решения вашего задания. 53 | - Добавьте решение задачи в файл ```solution.py```. 54 | 55 | Директория с заданием должна иметь следующую структуру: 56 | 57 | ```bash 58 | . 59 | ├── work 60 | | ├── new_task 61 | | | ├── description.md 62 | | | ├── new_task.py 63 | | | ├── solution.py 64 | | | ├── data.txt 65 | | | └── test_new_task.py 66 | . . 67 | ``` 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Voronov Vladimir 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Основы программирования на Python 2 | 3 | Добро пожаловать на курс основ программирования на языке программирования Python :snake: 4 | 5 | # Цели курса 6 | 7 | Этот курс преследует несколько основных целей: 8 | 9 | Курс долен предоставить подробное и наглядное изложение основных аспектов языка 10 | программирования Python. Курс имеет модульную структуру и построен по принципу 11 | "от простого к сложному". В самом начале предлагается ознакомиться с достоинствами и 12 | недостатками Python как одного из инструментов разработки программного обеспечения, 13 | а также с его основными принципами. В последующих частях приводится описание основных 14 | синтаксических конструкций и инструментов, которые предоставляет Python в стандартной 15 | библиотеке. Таким образом, можно сразу перейти к нужному материалу или пропустить 16 | часть известного. 17 | 18 | Курс должен служить структурированным пособием для специалистов, которые только 19 | начали изучать программирование и, в частности, Python. По завершению этого курса 20 | студент должен овладеть навыками написания собственных программ на Python, 21 | а также чтения чужого кода. 22 | 23 | Курс является частью образовательной программы по основам программирования и должен 24 | облегчить доступ студентов к полезным материалам. Однако, он направлен не только 25 | на студентов, но и будет полезен для людей, решивших начать изучения Python. 26 | 27 | # Для кого предназначен этот курс? 28 | 29 | Курс направлен на студентов инженерных специальностей, которые хотят начать 30 | изучения Python. Проходить курс могут не только студенты, изучающие в программирование 31 | в рамках учебного заведения, но и любой желающий в удобном для себя темпе, в этом 32 | случае необходимо самостоятельно выполнять примеры и задания. Для прохождения курса 33 | не требуется дополнительных знаний других языков или самого Python, однако, они будут, 34 | несомненно, полезны. 35 | 36 | # С чего начать? 37 | 38 | Вы можете использовать курс как справочник, выполняя примеры в вашей рабочей среде. 39 | О том, какое дополнительной программное обеспечение потребуется для прохождения 40 | курса будет описано в первой теме "Введение в Python". Также вы можете клонировать 41 | репозиторий в вашу локальную директорию, выполнив следующие команды в командной 42 | строке :octocat: : 43 | 44 | ```cmd 45 | git clone https://github.com/redb0/python-bp.git 46 | ``` 47 | 48 | Настоятельно рекомендуется выполнять каждый пример самостоятельно, а также модифицировать код. 49 | 50 | # Поддержка 51 | 52 | Если вы увлеченно интересуетесь Python, подумайте над тем, чтобы стать участником проекта. 53 | Если вы хотите принять участие в проекте создайте ```issues``` и предложите новую 54 | тему/задание/пример/литературу или исправление ошибок. 55 | 56 | Пожалуйста, прочтите наш [кодекс поведения](CODE_OF_CONDUCT.md) и [правила коллективного участия](CONTRIBUTING.md). Там 57 | описаны инструкции по открытию ```issues```, стандарты кодирования и прочие правила. 58 | 59 | # Обсуждения 60 | 61 | Если хотите узнать больше о тонкастях работы с Python не стесняйтесь посетить 62 | [обсуждения](https://github.com/redb0/python-bp/discussions). Там доступно: 63 | - [Обсуждение полезных ссылок](https://github.com/redb0/python-bp/discussions/11) 64 | 65 | Если вы не нашли то, что искали, или у вас есть интересные ссылки по Python или его 66 | экосистеме не стесняйтесь оставить комментарий. 67 | 68 | # Содержание 69 | 70 | 1. [**Введение в Python**](python_pd/01_intro/00_overview.md) 71 | 80 | 81 | 82 | 2. [**Синтаксис**](python_pd/02_syntax/00_overview.md) 83 | - [Простые типы данных (числа | логический | NoneType | строки)](python_pd/02_syntax/01_simple_types.ipynb) 84 | - [Переменные и выражения](python_pd/02_syntax/02_variables.ipynb) 85 | - [Управляющие конструкции](python_pd/02_syntax/03_control_structures.ipynb) 86 | - [Кратко о функциях](python_pd/02_syntax/04_functions.ipynb) 87 | - [Типизация](python_pd/02_syntax/05_dtyping.ipynb) 88 | 3. [**Коллекции**](python_pd/03_collections/00_overview.md) 89 | - [Базовые коллекции](python_pd/03_collections/basic_collections/00_overview.md) 90 | ([str](python_pd/03_collections/basic_collections/01_string.ipynb) | 91 | [list](python_pd/03_collections/basic_collections/02_list.ipynb) | 92 | [dict](python_pd/03_collections/basic_collections/03_dict.ipynb) | 93 | [tuple](python_pd/03_collections/basic_collections/04_tuple.ipynb) | 94 | [set](python_pd/03_collections/basic_collections/05_set.ipynb)) 95 | - [Изменяемые и неизменяемые типы данных](python_pd/03_collections/01_im_mutable_and_copy.ipynb) 96 | - [Включения в список | словарь | множество | кортеж](python_pd/03_collections/02_comprehensions.ipynb) 97 | - [Модуль ```collections```](python_pd/03_collections/03_collections.ipynb) 98 | - [Итераторы](python_pd/03_collections/04_iter.ipynb) 99 | - [Модуль ```itertools```](python_pd/03_collections/05_itertools.ipynb) 100 | 4. [**Функции**](python_pd/04_functions/00_overview.md) 101 | - [Аргументы функций](python_pd/04_functions/01_args.ipynb) 102 | - [Возвращаемое значение](python_pd/04_functions/02_return.ipynb) 103 | - [Анонимные функции](python_pd/04_functions/03_lambda.ipynb) 104 | - [Области видимости](python_pd/04_functions/04_legb.ipynb) 105 | - [Замыкания](python_pd/04_functions/06_closures.ipynb) 106 | - [Декораторы](python_pd/04_functions/07_decorators.ipynb) 107 | - [Генераторы](python_pd/04_functions/08_generators.ipynb) 108 | - [Модуль ```functools```](python_pd/04_functions/09_functools.ipynb) 109 | - [Исключения](python_pd/04_functions/10_exceptions.ipynb) 110 | 5. [**Файлы**](python_pd/05_files/00_overview.md) 111 | - [Файлы. Чтение и запись](python_pd/05_files/01_files.ipynb) 112 | - [Модуль ```io```](python_pd/05_files/02_io.ipynb) 113 | - [Менеджер контекста](python_pd/05_files/03_cmanagers.ipynb) 114 | - Модули для работы с разными форматами 115 | ([```txt```](python_pd/05_files/01_files.ipynb) | 116 | [```json```](python_pd/05_files/04_json.ipynb) | 117 | [```csv```](python_pd/05_files/05_csv.ipynb) | 118 | [```pickle```](python_pd/05_files/06_pickle.ipynb)) 119 | - Работа с путями 120 | ([```os.path```](python_pd/05_files/07_os_path.ipynb) | 121 | [```pathlib```](python_pd/05_files/08_pathlib.ipynb)) 122 | 6. [**Классы**](python_pd/06_classes/00_overview.md) 123 | - [Классы и экземпляры класса](python_pd/06_classes/01_class.ipynb) 124 | - [Атрибуты класса и экземпляра](python_pd/06_classes/02_attr.ipynb) 125 | - [Методы](python_pd/06_classes/03_methods.ipynb) 126 | - [Наследование](python_pd/06_classes/04_inheritance.ipynb) 127 | - ["Магические" методы](python_pd/06_classes/05_magic.ipynb) 128 | - [Протоколы](python_pd/06_classes/06_protocols.ipynb) 129 | - [Утиная типизация](python_pd/06_classes/07_duck_typing.ipynb) 130 | - [Дескрипторы и свойства](python_pd/06_classes/08_property.ipynb) 131 | - [Декораторы классов](python_pd/06_classes/09_decorators.ipynb) 132 | - [Абстрактные классы](python_pd/06_classes/10_abc.ipynb) 133 | - [Метаклассы](python_pd/06_classes/11_meta.ipynb) 134 | 7. [**Импорт**](python_pd/07_import/00_overview.md) 135 | - [Модули и пакеты](python_pd/07_import/01_modules.ipynb) 136 | - [Абсолютный и относительный импорт](python_pd/07_import/02_types_imports.ipynb) 137 | - [Циклический импорт](python_pd/07_import/02_types_imports.ipynb) 138 | - [Система импорта](python_pd/07_import/03_system.ipynb) 139 | - [Поиск модулей и пакетов](python_pd/07_import/04_search.ipynb) 140 | - [`pip`](python_pd/07_import/05_pip.ipynb) 141 | - [Виртуальное окружение](python_pd/07_import/06_venv.ipynb) 142 | - [PyPI](python_pd/07_import/07_pypi.ipynb) 143 | 8. [**Полезные библиотеки**](libraries.md) 144 | 9. [**Примеры плохого кода**](python_pd/badcode.ipynb) 145 | 146 | # TODO 147 | 148 | ### Введение 149 | - [x] Введение 150 | - [x] [1. Синтаксис] Простые типы 151 | - [x] [2. Синтаксис] Переменные 152 | - [x] [3. Синтаксис] Управляющие конструкции 153 | - [x] [4. Синтаксис] Коротко о функция 154 | - [x] [5. Синтаксис] Типизация 155 | 156 | ### Коллекции 157 | - [x] [1. Коллекции] Неизменяемые и изменяемые типы данных 158 | - [x] [2. Коллекции] Включения 159 | - [x] [3. Коллекции] `collections` 160 | - [x] [4. Коллекции] Итераторы 161 | - [x] [5. Коллекции] `itertools` 162 | 163 | ### Функции 164 | - [x] [1. Функции] Аргументы 165 | - [x] [2. Функции] `return` 166 | - [x] [3. Функции] lambda-функции 167 | - [x] [4. Функции] Пространства имен 168 | - [x] [5. Функции] Рекурсия 169 | - [x] [6. Функции] Замыкания 170 | - [x] [7. Функции] Декораторы 171 | - [x] [8. Функции] Генераторы 172 | - [x] [9. Функции] `functools` 173 | - [x] [10. Функции] Исключения 174 | 175 | ### Файлы 176 | - [x] [1. Файлы] Файлы 177 | - [x] [2. Файлы] `io` 178 | - [x] [3. Файлы] Менеджеры контекста 179 | - [x] [4. Файлы] `json` 180 | - [x] [5. Файлы] `csv` 181 | - [x] [6. Файлы] `pickle` 182 | - [x] [7. Файлы] `os.path` 183 | - [x] [8. Файлы] `pathlib` 184 | 185 | ### Классы 186 | - [x] [1. Классы] Классы 187 | - [x] [2. Классы] Атрибуты 188 | - [x] [3. Классы] Методы 189 | - [x] [4. Классы] Наследование 190 | - [x] [5. Классы] Магические методы 191 | - [x] [6. Классы] Протоколы 192 | - [x] [7. Классы] Утиная типизация 193 | - [x] [8. Классы] Свойства 194 | - [ ] [9. Классы] Декораторы 195 | - [ ] [10. Классы] Абстрактные классы 196 | - [ ] [11. Классы] Метаклассы 197 | 198 | ### Импорт 199 | - [ ] [1. Импорт] Модули и пакеты 200 | - [ ] [2. Импорт] Абсолютный и относительный импорт 201 | - [ ] [3. Импорт] Циклический импорт 202 | - [ ] [4. Импорт] Система импорта 203 | - [ ] [5. Импорт] Поиск модулей и пакетов 204 | - [ ] [6. Импорт] `pip` 205 | - [ ] [7. Импорт] Виртуальное окружение 206 | - [ ] [8. Импорт] PyPI 207 | 208 | ### Задания 209 | - [ ] Синтаксис 210 | - [ ] Поиск [чисел Капрекара](https://en.wikipedia.org/wiki/Kaprekar_number) 211 | - [ ] Поиск [констант Капрекара](https://en.wikipedia.org/wiki/Kaprekar%27s_routine) 212 | - [ ] Коллекции 213 | - [ ] Функции 214 | - [ ] Файлы 215 | - [ ] Классы 216 | -------------------------------------------------------------------------------- /libraries.md: -------------------------------------------------------------------------------- 1 | # Краткий обзор стандартной библиотеки Python 2 | 3 | Стандартная библиотеку Python обширна. Она содержит большое количество 4 | полезных модулей, позволяющих решить множество задач. С этим связано 5 | одно из преимуществ Python: батарейки в комплекте. Ознакомиться с 6 | перечнем модулей стандартной библиотеки можно по ссылке: 7 | https://docs.python.org/3/library/index.html 8 | 9 | В стандартной библиотеке Вы сможете найти: 10 | 11 | 1) полезные типы данных 12 | (`collections` | `datetime` | `enum` | `decimal` и другие); 13 | 2) элементы функционального программирования 14 | (`itertools` | `functools` | `operator`); 15 | 3) библиотеки для сериализации/десериализации данных и работе с файлами 16 | (`json` | `csv` | `xml` | `pickle` | `shelve` | `sqlite3` | `zlib` и другие); 17 | 4) инструменты для работы с ОС 18 | (`os` | `io` | `argparse` | `logging` и другие); 19 | 5) модули для параллельных вычислений 20 | (`threading` | `multiprocessing` | `subprocess` | `asyncio`); 21 | 6) инструменты для работы с сетью 22 | (`asyncio` | `socket` | `ssl` | `email` | `html` | `urllib` | `uuid`); 23 | 7) вспомогательные инструменты 24 | (`typing` | `pydoc` | `doctest` | `unittest` | `timeit` | `venv`); 25 | 8) модули кастомизации импорта 26 | (`importlib`); 27 | 9) и много интересных специализированных модулей 28 | (`parser` | `ast` | `symbol` и другие). 29 | 30 | Некоторые из них были рассмотрены в соответствующих главах курса. 31 | 32 | # Подборка полезных сторонних покетов 33 | 34 | Сайт pypi.org с каталогом сторонних пакетов: 35 | https://pypi.org/ 36 | 37 | ## 1. Веб 38 | 39 | - django ([офф. сайт](https://www.djangoproject.com/), [github](https://github.com/django/django)) 40 | - Tornado ([офф. сайт](https://www.tornadoweb.org/en/stable/), [github](https://github.com/tornadoweb/tornado)) 41 | - Brython ([офф. сайт](https://brython.info/), [github](https://github.com/brython-dev/brython)) 42 | - Pyodide ([github](https://github.com/iodide-project/pyodide)) 43 | - Requests ([офф. сайт](https://requests.readthedocs.io/en/master/), [github](https://github.com/psf/requests)) 44 | 45 | ## 2. Десктоп 46 | 47 | - PyQt5 ([github](https://github.com/PyQt5)) 48 | - PySide6 ([офф. сайт](https://wiki.qt.io/Qt_for_Python), [github](https://github.com/PySide)) 49 | 50 | ## 3. Мобилки 51 | 52 | - kivy ([офф. сайт](https://kivy.org/#home), [github](https://github.com/kivy/kivy)) 53 | - qpython ([офф. сайт](https://www.qpython.com/), [github](https://github.com/qpython-android/qpython/releases)) 54 | 55 | ## 4. Разработка игр 56 | 57 | - Pygame ([офф. сайт](https://www.pygame.org/news), [github](https://github.com/pygame/pygame)) 58 | - pyxel ([github](https://github.com/kitao/pyxel?utm_source=mybridge&utm_medium=blog&utm_campaign=read_more)) 59 | - RenPy ([офф. сайт](https://www.renpy.org/), [github](https://github.com/renpy/renpy)) 60 | 61 | ## 5. Что-то посчитать 62 | 63 | - numpy ([офф. сайт](https://numpy.org/), 64 | [github](https://github.com/numpy/numpy), 65 | [документация](https://numpy.org/doc/stable/), 66 | [туториал](https://numpy.org/doc/stable/user/tutorials_index.html)) 67 | - sympy ([офф. сайт](https://www.sympy.org/en/index.html), 68 | [github](https://github.com/sympy/sympy), 69 | [документация](https://docs.sympy.org/latest/index.html), 70 | [туториал](https://docs.sympy.org/latest/tutorial/index.html)) 71 | - scipy ([офф. сайт](https://www.scipy.org/), 72 | [github](https://github.com/scipy/scipy/), 73 | [документация](https://docs.scipy.org/doc/), 74 | [туториал](https://docs.scipy.org/doc/scipy/reference/tutorial/index.html)) 75 | - Theano ([github](https://github.com/Theano/Theano)) - еще одна библиотека для вычислений (разработка прекращена) 76 | - PyDSTool ([офф. сайт](https://pydstool.github.io/PyDSTool/FrontPage.html), 77 | [github](https://github.com/robclewley/pydstool), 78 | [документация](https://pydstool.github.io/PyDSTool/ToolboxDocumentation.html), 79 | [туториал](https://pydstool.github.io/PyDSTool/Tutorial.html)) 80 | - QuTiP ([офф. сайт](http://qutip.org/), 81 | [github](https://github.com/qutip), 82 | [документация](http://qutip.org/documentation.html), 83 | [туториал](http://qutip.org/tutorials.html)) 84 | 85 | Что есть еще? 86 | - [AstroPy](https://www.astropy.org/) - астрономия 87 | - [PsychoPy](https://www.psychopy.org/) - нейробиология, психофизика, психология. 88 | - [BioPython](https://biopython.org/) - биоинформатика 89 | - [PyChem](https://pubmed.ncbi.nlm.nih.gov/16882648/) - химия 90 | - [Shapely](https://shapely.readthedocs.io/en/stable/) - география 91 | 92 | И еще: 93 | - [numdifftools](https://github.com/pbrod/numdifftools) - производные в любом проявлении 94 | 95 | 96 | ## 6. Что-то визуализировать 97 | 98 | - matplotlib ([офф. сайт](https://matplotlib.org/), 99 | [github](https://github.com/matplotlib/matplotlib), 100 | [документация](https://matplotlib.org/contents.html), 101 | [туториал](https://matplotlib.org/tutorials/index.html)) 102 | - seaborn ([офф. сайт](https://seaborn.pydata.org/), 103 | [github](https://github.com/mwaskom/seaborn), 104 | [туториал](https://seaborn.pydata.org/tutorial.html)) 105 | - Mayavi ([офф. сайт](https://docs.enthought.com/mayavi/mayavi/), 106 | [github](https://github.com/enthought/mayavi)) 107 | - manim ([github](https://github.com/3b1b/manim), 108 | [документация](https://eulertour.com/docs/)) 109 | - Dash ([офф. сайт](http://dash.plotly.com/), [github](https://github.com/plotly/dash)) 110 | 111 | ## 7. Как собрать данные? 112 | 113 | - BeautifulSoup ([офф. сайт](), [github]()) 114 | - scrapy ([офф. сайт](), [github]()) 115 | 116 | ## 8. А как хранить будем? 117 | 118 | - psycopg2/3 ([офф. сайт](https://www.psycopg.org/), [github](https://github.com/psycopg/psycopg2)) - PostgreSQL 119 | - SqlAlchemy ([офф. сайт](https://www.sqlalchemy.org/), 120 | [github](https://github.com/sqlalchemy/sqlalchemy)) - PostgreSQL | MySQL | SQLite | Oracle | Microsoft SQL Server 121 | - pyobdc ([github](https://github.com/mkleehammer/pyodbc)) 122 | 123 | ## 9. Анализ данных 124 | 125 | - pandas ([офф. сайт](https://pandas.pydata.org/), 126 | [github](https://github.com/pandas-dev/pandas), 127 | [документация](https://pandas.pydata.org/docs/), 128 | [туториал](https://pandas.pydata.org/docs/user_guide/index.html)) 129 | - statsmodels ([офф. сайт](https://www.statsmodels.org/stable/index.html), 130 | [github](https://github.com/statsmodels/statsmodels), 131 | [туториал](https://www.statsmodels.org/stable/user-guide.html)) 132 | - nltk ([офф. сайт](http://www.nltk.org/), [github](https://github.com/nltk/nltk)) 133 | 134 | ## 10. Все для создания Skynet 135 | 136 | - scikit-learn ([офф. сайт](https://scikit-learn.org/stable/), [github](https://github.com/scikit-learn/scikit-learn)) 137 | - xgboost ([офф. сайт](https://xgboost.readthedocs.io/en/latest/), [github](https://github.com/dmlc/xgboost)) 138 | - OpenCV ([офф. сайт](https://docs.opencv.org/master/), [github](https://github.com/skvark/opencv-python)) 139 | - pytorch ([офф. сайт](https://pytorch.org/), [github](https://github.com/pytorch/pytorch)) 140 | - tensorflow ([офф. сайт](https://www.tensorflow.org/learn), [github](https://github.com/tensorflow/tensorflow)) 141 | - keras ([офф. сайт](https://keras.io/), [github](https://github.com/keras-team/keras)) 142 | 143 | ## 11. Качество кода 144 | 145 | - pylint ([офф. сайт](https://github.com/PyCQA/pylint), [github](https://www.pylint.org/)) 146 | - flake8 ([офф. сайт](https://flake8.pycqa.org/en/latest/), [github](https://github.com/PyCQA/flake8)) 147 | - pylama ([офф. сайт](http://klen.github.io/pylama.html), [github](https://github.com/klen/pylama)) 148 | - mypy ([офф. сайт](http://www.mypy-lang.org/), [github](https://github.com/python/mypy)) 149 | - MonkeyType ([github](https://github.com/Instagram/MonkeyType)) 150 | - pyannotate ([github](https://github.com/dropbox/pyannotate)) 151 | 152 | ## 12. Просто полезные штуки 153 | 154 | - pytest ([офф. сайт](https://docs.pytest.org/en/stable/), [github](https://github.com/pytest-dev/pytest)) 155 | - virtualenv ([офф. сайт](https://virtualenv.pypa.io/en/latest/), [github](https://github.com/pypa/virtualenv)) 156 | - sphinx ([офф. сайт](https://www.sphinx-doc.org/en/master/), [github](https://github.com/sphinx-doc/sphinx)) 157 | - Jupyter ([офф. сайт](https://jupyter.org/), [github](https://jupyter.org/)) 158 | - geopy ([офф. сайт](https://geopy.readthedocs.io/en/stable/), [github](https://github.com/geopy/geopy)) 159 | - tabulate ([github](https://github.com/astanin/python-tabulate)) 160 | - Pillow ([офф. сайт](https://python-pillow.org/), [github](https://github.com/python-pillow/Pillow)) 161 | 162 | ## Где применять? 163 | 164 | 1) Открытие гравитационных волн: 165 | - https://numpy.org/case-studies/gw-discov/ 166 | - https://www.youtube.com/watch?v=7mcHknWWzNI&feature=youtu.be 167 | 2) Первое фото черной дыры: 168 | - https://numpy.org/case-studies/blackhole-image/ 169 | -------------------------------------------------------------------------------- /python_pd/01_intro/00_overview.md: -------------------------------------------------------------------------------- 1 | # 1. Введение в Python 2 | 3 | В этом разделе даются общие представления о языке программирования Python, его 4 | достоинствах и недостатках. Во второй половине этого раздела (начиная с п. 1.6) 5 | приводится описание примеров и то, с чего стоит начать изучение курса, а также 6 | немного об инструментах, которые могут потребоваться. 7 | 8 | - [1.1 О Python](01_introduction.md) 9 | - [1.2 Почему стоит изучать Python?](01_introduction.md#почему-стоит-изучать-python?) 10 | - [1.3 Недостатки Python](01_introduction.md#недостатки-python) 11 | - [1.4 Принципы Python](01_introduction.md#принциры-python) 12 | - [1.5 Руководство по написанию кода](01_introduction.md#руководство-по-написанию-кода) 13 | - [1.6 О примерах кода](01_introduction.md#о-примерах-кода) 14 | - [1.7 Необходимое ПО и зависимости](01_introduction.md#необходимое-по-и-зависимости) 15 | - [1.8 Проверка кода на соответствие стандарту](01_introduction.md#проверка-кода-на-соответствие-стандарту) 16 | - [1.9 Python и командная строка](01_introduction.md#python-и-командная-строка) 17 | - [1.10 Виртуальное окружение](01_introduction.md#виртуальное-окружение) 18 | - [1.11 Полезные ссылки](01_introduction.md#полезные-ссылки) 19 | 20 | [К содержанию](../../README.md) 21 | 22 | [2. Синтаксис](../02_syntax/00_overview.md) 23 | -------------------------------------------------------------------------------- /python_pd/01_intro/02_installation.md: -------------------------------------------------------------------------------- 1 | # Установка интерпретатора Python 2 | 3 | 1. Зайти на официальный сайт [python.org](https://www.python.org/) 4 | 2. Загрузите интерпретатор Python 5 | - Для Windows 6 | 7 | ![Для Windows](image/download_windows.png) 8 | 9 | - Для Mac OS 10 | 11 | Выберите в списке операционных систем macOS 12 | ![Для Mac OS](image/download_mac_1.png) 13 | 14 | Выберите версию интерпретатора (3.10.2) 15 | ![Для Mac OS](image/download_mac_2.png) 16 | 17 | Выберите дистрибутив для macOS 18 | ![Для Mac OS](image/download_mac_3.png) 19 | 20 | 3. Запустите установку Python 21 | 22 | Выберите установку с настройками по умолчанию, а также поставьте галочку напротив "Add Python 3.10 to PATH" 23 | ![Для Mac OS](image/installation.png) 24 | 25 | 4. Проверьте корректность установки, выполнив следующие инструкции 26 | - Откройте консоль, нажав клавиши `Win`+`R`, введите `cmd` и нажмите `Enter` (для Windows) 27 | - Введите команду `python --version` 28 | - Убедитесь, что появилась надпись `Python 3.10.2` 29 | 30 | 5. Запустите консольный терминал Python, введя команду `python` 31 | 6. Экспериментируйте! 32 | -------------------------------------------------------------------------------- /python_pd/01_intro/image/download_mac_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/01_intro/image/download_mac_1.png -------------------------------------------------------------------------------- /python_pd/01_intro/image/download_mac_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/01_intro/image/download_mac_2.png -------------------------------------------------------------------------------- /python_pd/01_intro/image/download_mac_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/01_intro/image/download_mac_3.png -------------------------------------------------------------------------------- /python_pd/01_intro/image/download_windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/01_intro/image/download_windows.png -------------------------------------------------------------------------------- /python_pd/01_intro/image/installation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/01_intro/image/installation.png -------------------------------------------------------------------------------- /python_pd/02_syntax/00_overview.md: -------------------------------------------------------------------------------- 1 | # 2. Синтаксис 2 | 3 | В этом разделе рассматривается синтаксис Python, а также некоторые аспекты 4 | работы с именами или переменными. В заключении будет рассмотрены особенности 5 | динамической типизации в Python. 6 | 7 | - [2.1 Простые типы данных](01_simple_types.ipynb) 8 | - [2.2 Переменные и выражения](02_variables.ipynb) 9 | - [2.3 Управляющие конструкции](03_control_structures.ipynb) 10 | - [2.4 Кратко о функциях](04_functions.ipynb) 11 | - [2.5 Типизация](05_dtyping.ipynb) 12 | 13 | [К содержанию](../../README.md) 14 | 15 | [3. Коллекции](../03_collections/00_overview.md) 16 | -------------------------------------------------------------------------------- /python_pd/02_syntax/01_simple_types.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.8.4-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Простые типы данных\n", 27 | "## Числа\n", 28 | "\n", 29 | "В Python реализованы три вида чисел:\n", 30 | "\n", 31 | "- целые числа (```int```);\n", 32 | "- числа с плавающей точкой (```float```);\n", 33 | "- комплексные числа (```complex```).\n", 34 | "\n", 35 | "В скобках указано обозначение типов, которые используются в Python. В Python текст после символа ```#``` обозначает комментарий. Для ясности в нем указывается тип числа, а также поясняющий текст." 36 | ], 37 | "cell_type": "markdown", 38 | "metadata": {} 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "# int\n", 47 | "42" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "# float\n", 57 | "42.0 # указывается целая и дробная часть\n", 58 | "0.42\n", 59 | "42. # с указанием только целой части, в случае если дробная часть = 0\n", 60 | ".42 # с указанием только дробной части, в случае если целая часть = 0\n", 61 | "4.2e1 # экспоненциальная нотация (4.2 * 10**1)" 62 | ] 63 | }, 64 | { 65 | "cell_type": "code", 66 | "execution_count": null, 67 | "metadata": {}, 68 | "outputs": [], 69 | "source": [ 70 | "# complex\n", 71 | "# в комплексных числах мнимая единица обозначается как j\n", 72 | "1 + 4j\n", 73 | "1 + 0j\n", 74 | "4j" 75 | ] 76 | }, 77 | { 78 | "source": [ 79 | "Python помимо чисел в десятичной системе счисления позволяет использовать двоичную, восьмеричную и шестнадцатеричную системы счисления. " 80 | ], 81 | "cell_type": "markdown", 82 | "metadata": {} 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "0b011 # 3 в двоичной системе\n", 91 | "0o017 # 15 в восьмеричной системе\n", 92 | "0xbadc0fee # 3134984174 в шестнадцатеричной системе" 93 | ] 94 | }, 95 | { 96 | "source": [ 97 | "## Логический тип\n", 98 | "\n", 99 | "В Python логический тип имеет обозначение ```bool```.\n", 100 | "\n", 101 | "Логический тип имеет только две константы: ```True``` (истина) и ```False``` (ложь). Они могут использоваться в различных условиях.\n" 102 | ], 103 | "cell_type": "markdown", 104 | "metadata": {} 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "# bool\n", 113 | "True\n", 114 | "False" 115 | ] 116 | }, 117 | { 118 | "source": [ 119 | "## Странный тип или NoneType\n", 120 | "\n", 121 | "Специальный тип ```NoneType``` имеет только одну константу ```None```, буквально обозначающую \"ничего\". Константа предназначена исключительно для сравнения и использования в условиях." 122 | ], 123 | "cell_type": "markdown", 124 | "metadata": {} 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": null, 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "# Nonetype\n", 133 | "None" 134 | ] 135 | }, 136 | { 137 | "source": [ 138 | "## Строки\n", 139 | "\n", 140 | "В Python строки представлены типом ```str```. Создать строку можно, заключив что-либо в кавычки. Если внутри кавычек ничего нет, то строка пустая. Python разрешает использовать разные виды кавычек для обозначения строк:\n", 141 | "\n", 142 | "- одинарные ```'str'```\n", 143 | "- двойные ```\"str\"```\n", 144 | "- тройные одинарные ```'''str'''```\n", 145 | "- тройные двойные ```\"\"\"str\"\"\"```\n" 146 | ], 147 | "cell_type": "markdown", 148 | "metadata": {} 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": null, 153 | "metadata": {}, 154 | "outputs": [], 155 | "source": [ 156 | "# str\n", 157 | "'monty_python'\n", 158 | "\"monty_python\"\n", 159 | "'''monty_python'''\n", 160 | "\"\"\"monty_python\"\"\"" 161 | ] 162 | }, 163 | { 164 | "source": [ 165 | "Разные кавычки позволяют использовать, например, двойные кавычки внутри одинарных и наоборот." 166 | ], 167 | "cell_type": "markdown", 168 | "metadata": {} 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": null, 173 | "metadata": {}, 174 | "outputs": [], 175 | "source": [ 176 | "'answer to the question is \"42\"'" 177 | ] 178 | }, 179 | { 180 | "source": [ 181 | "Тройные кавычки используются в редких случаях обозначения многострочных строк. Не используйте их для создания коротких строк. \n", 182 | "\n", 183 | "Использование двойных или одинарных кавычек остается делом вкуса. Определитесь с наиболее понравившимися кавычками и используйте их постоянно. Не стоит использовать для обозначения простых строк разные виды кавычек в разных местах программы, за исключением вложенных кавычек." 184 | ], 185 | "cell_type": "markdown", 186 | "metadata": {} 187 | }, 188 | { 189 | "source": [ 190 | "## Преобразование типов\n", 191 | "\n", 192 | "В Python необходимо явно приводить типы, никакого неявного преобразования \"под капотом\" не производится. Об этом более подробно будет рассказано в следующих разделах. Пока затронем только тему преобразования типов друг в друга. Напомним, есть 5 простых типов:\n", 193 | "- ```int```\n", 194 | "- ```float```\n", 195 | "- ```complex```\n", 196 | "- ```bool```\n", 197 | "- ```str```\n", 198 | "- ```NoneType```\n", 199 | "\n", 200 | "Из этих типов ```NoneType``` стоит обособленно. Он имеет только одну константу ```None``` и в него нельзя преобразовать никакие другие типы.\n", 201 | "\n", 202 | "Все остальные типы имеют специальные функции, названия которых совпадают с названиями типов. Эти функции предназначены для преобразования типов. Рассмотрим получение каждого типа данных из всех остальных. Здесь в комментариях после знака ```->``` указано какой результат будет после преобразования." 203 | ], 204 | "cell_type": "markdown", 205 | "metadata": {} 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": null, 210 | "metadata": {}, 211 | "outputs": [], 212 | "source": [ 213 | "# Получим int из остальных\n", 214 | "# При преобразовании из float число просто округляется вниз,\n", 215 | "# т.е. дробная часть отбрасывается\n", 216 | "int(42.1) # -> 42\n", 217 | "int(42.6) # -> 42\n", 218 | "\n", 219 | "# Конвертировать complex в int нельзя\n", 220 | "int(1 + 2j) # -> Ошибка\n", 221 | "\n", 222 | "# Тип bool образован из int, поэтому результат будет таким\n", 223 | "int(True) # -> 1\n", 224 | "int(False) # -> 0\n", 225 | "\n", 226 | "# Если нужно преобразовать строку в int, нужно следить \n", 227 | "# чтобы она содержала корректное целое число (только цифры)\n", 228 | "int('42') # -> 42\n", 229 | "int('42.0') # -> Ошибка\n", 230 | "int('asd') # -> Ошибка" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": null, 236 | "metadata": {}, 237 | "outputs": [], 238 | "source": [ 239 | "# Получим float из остальных\n", 240 | "# При преобразовании из int дробная часть становиться равна 0\n", 241 | "float(42) # -> 42.0\n", 242 | "float(42.1) # -> 42.1\n", 243 | "\n", 244 | "# Конвертировать complex вo float нельзя\n", 245 | "float(1 + 2j) # -> Ошибка\n", 246 | "\n", 247 | "# Тип bool образован из int, поэтому результат будет таким\n", 248 | "float(True) # -> 1.0\n", 249 | "float(False) # -> 0.0\n", 250 | "\n", 251 | "# Если нужно преобразовать строку во float, нужно следить \n", 252 | "# чтобы она содержала корректное целое число (только цифры) \n", 253 | "# или число с плавающей точкой\n", 254 | "float('42') # -> 42.0\n", 255 | "float('42.5') # -> 42.5\n", 256 | "float('.5') # -> 0.5\n", 257 | "float('1.') # -> 1.0\n", 258 | "float('1e10') # -> 10000000000.0\n", 259 | "float('asd') # -> Ошибка" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": null, 265 | "metadata": {}, 266 | "outputs": [], 267 | "source": [ 268 | "# Получим str из остальных\n", 269 | "str(42) # -> '42'\n", 270 | "str(42.1) # -> '42.1'\n", 271 | "str(1 + 2j) # -> '(1+2j)'\n", 272 | "\n", 273 | "str(True) # -> 'True'\n", 274 | "str(False) # -> 'False'\n", 275 | "\n", 276 | "# None можно преобразовать в строку\n", 277 | "str(None) # 'None'" 278 | ] 279 | }, 280 | { 281 | "source": [ 282 | "## \"Ложные\" и \"истинные\" значения или преобразования в ```bool```\n", 283 | "\n", 284 | "Преобразование типов в ```bool``` одно из самых полезных. Оно повсеместно используется в различного рода условиях. Поэтому для правильного и лаконичного изложение своей мысли в виде кода важно знать правила по преобразованию прочих типов в ```bool```. Правило здесь довольно простое. В Python у каждого типа данных есть две группы значений. Значения первой группы эквивалентны ```True``` и называются истинными значениями или [Truth value](https://docs.python.org/3/library/stdtypes.html). Вторая группа состоит из ложных значений, которые эквивалентны ```False```.\n", 285 | "\n", 286 | "Правило заключается в следующем. Следующие значения всегда эквивалентны ```False```:\n", 287 | "- ноль для любых числовых типов (```0```, ```0.0```, ```0 + 0j```)\n", 288 | "- пустая строка (```''```)\n", 289 | "- False\n", 290 | "- None\n", 291 | "\n", 292 | "Любые другие значения всегда будут эквивалентны ```True```." 293 | ], 294 | "cell_type": "markdown", 295 | "metadata": {} 296 | }, 297 | { 298 | "cell_type": "code", 299 | "execution_count": null, 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "# преобразования в bool\n", 304 | "bool(42) # -> True\n", 305 | "bool(-1) # -> True\n", 306 | "bool(1 + 2j) # -> True\n", 307 | "bool(0.0) # -> False\n", 308 | "bool(0j) # -> False\n", 309 | "\n", 310 | "bool('not True') # -> True\n", 311 | "bool('') # -> False\n", 312 | "\n", 313 | "bool(None) # -> False" 314 | ] 315 | } 316 | ] 317 | } -------------------------------------------------------------------------------- /python_pd/02_syntax/04_functions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Коротко о функциях\n", 27 | "\n", 28 | "## Синтаксис\n", 29 | "\n", 30 | "В Python объявление функций происходит с помощью ключевого слова def. Формально синтаксис можно записать следующим образом:\n", 31 | "\n", 32 | "```python\n", 33 | "def identifier([parameter_list]):\n", 34 | " function_suite\n", 35 | "```\n", 36 | "\n", 37 | "За ключевым словом ```def``` следует имя (идентификатор) функции ```identifier```. Ограничения на имена функций аналогичны ограничениям на прочие идентификаторы. За тем в круглых скобках следует перечисление аргументов функции ```parameter_list```, если таковые необходимы. После закрывающей круглой скобки идет двоеточие, отделяющее объявление функции и её тело. Тело функции ```function_suite``` следует писать, делая отступ. Оно может содержать одну или несколько инструкций. В качестве тела функции может использоваться ключевое слово ```pass```, которое ничего не выполняет. Таким образом, простейшая функция может выглядеть как:" 38 | ], 39 | "cell_type": "markdown", 40 | "metadata": {} 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": null, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "def foo(): # определение функции\n", 49 | " pass # тело функции" 50 | ] 51 | }, 52 | { 53 | "source": [ 54 | "Для возвращения какого-либо объекта из функции используется ключевое слово ```return```. Следующая функция будет всегда возвращать одно значение - ```42```." 55 | ], 56 | "cell_type": "markdown", 57 | "metadata": {} 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "def foo():\n", 66 | " return 42" 67 | ] 68 | }, 69 | { 70 | "source": [ 71 | "Вызывать функции можно, указав идентификатор и значения параметров, заключенные в круглые скобки. Вызов функции должен находиться после ее определения." 72 | ], 73 | "cell_type": "markdown", 74 | "metadata": {} 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 1, 79 | "metadata": {}, 80 | "outputs": [ 81 | { 82 | "output_type": "stream", 83 | "name": "stdout", 84 | "text": [ 85 | "42\n" 86 | ] 87 | } 88 | ], 89 | "source": [ 90 | "def foo():\n", 91 | " return 42\n", 92 | "\n", 93 | "print(foo())" 94 | ] 95 | }, 96 | { 97 | "source": [ 98 | "Если функция не должна ничего возвращать его писать не обязательно. Однако стоит учитывать, что функции в Python всегда возвращают значение и если ключевое слово ```return``` не указано, функция по умолчанию вернет ```None```, т.е." 99 | ], 100 | "cell_type": "markdown", 101 | "metadata": {} 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 3, 106 | "metadata": {}, 107 | "outputs": [ 108 | { 109 | "output_type": "stream", 110 | "name": "stdout", 111 | "text": [ 112 | "foo() -> None\nbar() -> None\nbaz() -> None\n" 113 | ] 114 | } 115 | ], 116 | "source": [ 117 | "def foo():\n", 118 | " pass\n", 119 | "\n", 120 | "def bar():\n", 121 | " return None\n", 122 | "\n", 123 | "def baz():\n", 124 | " return\n", 125 | "\n", 126 | "print('foo() ->', foo())\n", 127 | "print('bar() ->', bar())\n", 128 | "print('baz() ->', baz())" 129 | ] 130 | }, 131 | { 132 | "source": [ 133 | "## Аргументы\n", 134 | "\n", 135 | "Python позволяет задавать два вида аргументов у функции: позиционные или обязательные и ключевые или необязательные. Позиционные аргументы задаются перечислением их идентификаторов через запятую." 136 | ], 137 | "cell_type": "markdown", 138 | "metadata": {} 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 3, 143 | "metadata": {}, 144 | "outputs": [ 145 | { 146 | "output_type": "stream", 147 | "name": "stdout", 148 | "text": [ 149 | "8\n16\n" 150 | ] 151 | } 152 | ], 153 | "source": [ 154 | "# Функция foo принимает три позиционных аргумента a, b и c\n", 155 | "def foo(a, b, c):\n", 156 | " return 2 * a + b * c\n", 157 | "\n", 158 | "# вызвать функцию можно передав значения через запятую\n", 159 | "print(foo(1, 2, 3))\n", 160 | "\n", 161 | "# можно явно указать имена и значения\n", 162 | "print(foo(a=3, b=2, c=5))" 163 | ] 164 | }, 165 | { 166 | "source": [ 167 | "Один из способов определить функцию с ключевыми аргументами -- это указать у аргумента через пробел значение по умолчанию." 168 | ], 169 | "cell_type": "markdown", 170 | "metadata": {} 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 5, 175 | "metadata": {}, 176 | "outputs": [ 177 | { 178 | "output_type": "stream", 179 | "name": "stdout", 180 | "text": [ 181 | "1\n7\n8\n" 182 | ] 183 | } 184 | ], 185 | "source": [ 186 | "def foo(a, b, c=0):\n", 187 | " return a + 3 * b - 2 * c\n", 188 | "\n", 189 | "# значения передаются поочередно, c будет равно 3\n", 190 | "print(foo(1, 2, 3))\n", 191 | "\n", 192 | "# если у ключевых аргументов указано значение по умолчанию,\n", 193 | "# его можно не передавать\n", 194 | "print(foo(1, 2))\n", 195 | "\n", 196 | "# можно явно указывать значения у ключевых аргументов\n", 197 | "print(foo(10, 2, c=4))" 198 | ] 199 | }, 200 | { 201 | "source": [ 202 | "Более подробно функции будут рассмотрены в пункте 4 \"Функции\".\n", 203 | "\n", 204 | "# Некоторые встроенные функции\n", 205 | "\n", 206 | "Интерпретатор Python предоставляет некоторое количество встроенных функций. С полным перечнем можно ознакомиться в [документации](https://docs.python.org/3/library/functions.html). О некоторых уже упоминалось, например, ```print```, ```input```, ```int```, ```bool```, ```str```, ```complex``` и ```float```. Вот пример использования некоторых из них." 207 | ], 208 | "cell_type": "markdown", 209 | "metadata": {} 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 16, 214 | "metadata": {}, 215 | "outputs": [ 216 | { 217 | "output_type": "stream", 218 | "name": "stdout", 219 | "text": [ 220 | "abs: 5\nchr ё\nord: 68\nmax: 20\nmin: 0\n--------------------------------------------------\nHelp on built-in function abs in module builtins:\n\nabs(x, /)\n Return the absolute value of the argument.\n\nhelp: None\n" 221 | ] 222 | } 223 | ], 224 | "source": [ 225 | "# модуль числа\n", 226 | "print('abs:', abs(-5))\n", 227 | "\n", 228 | "# получение символа по коду Unicode\n", 229 | "print('chr:', chr(1105))\n", 230 | "# обратная chr, получения кода по символу\n", 231 | "print('ord:', ord('D'))\n", 232 | "\n", 233 | "# максимум, принимают хотябы два аргумента\n", 234 | "print('max:', max(1, 20, 3, 6, 1, 0))\n", 235 | "# минимум\n", 236 | "print('min:', min(1, 20, 3, 6, 1, 0))\n", 237 | "\n", 238 | "print('-' * 50)\n", 239 | "# получение справки об объекте\n", 240 | "print('help:', help(abs))" 241 | ] 242 | } 243 | ] 244 | } -------------------------------------------------------------------------------- /python_pd/02_syntax/05_dtyping.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.8.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "5be696dc-7900-45eb-ba9e-444d8f184671", 18 | "display_name": "'Python Interactive'" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Типизация в Python\n", 27 | "\n", 28 | "## Динамическая типизация\n", 29 | "\n", 30 | "Python $-$ это язык программирования с динамической типизацией. Это означает, что переменная в разные моменты времени исполнения или в разных местах программы может быть связана с объектами разных типов. Противоположностью динамической типизации служит статическая типизация. Примерами языков со статической типизацией будут C++, Go, Java.\n", 31 | "\n", 32 | "Преимущества динамической типизации заключается в отсутствии необходимости заботиться о преобразовании типов и более простой реализации программ.\n" 33 | ], 34 | "cell_type": "markdown", 35 | "metadata": {} 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 1, 40 | "metadata": {}, 41 | "outputs": [ 42 | { 43 | "output_type": "stream", 44 | "name": "stdout", 45 | "text": [ 46 | "(1) foo = 42 (int)\n(2) foo = 42.0 (float)\n(3) foo = False (bool)\n(4) foo = bar (str)\n" 47 | ] 48 | } 49 | ], 50 | "source": [ 51 | "foo = 42\n", 52 | "print('(1) foo =', foo, '(int)')\n", 53 | "foo = 42.\n", 54 | "print('(2) foo =', foo, '(float)')\n", 55 | "foo = False\n", 56 | "print('(3) foo =', foo, '(bool)')\n", 57 | "foo = 'bar'\n", 58 | "print('(4) foo =', foo, '(str)')" 59 | ] 60 | }, 61 | { 62 | "source": [ 63 | "## Сильная типизация\n", 64 | "\n", 65 | "Python $-$ это язык с сильной динамической типизацией. Это означает, что неявного преобразования типов нет. Так, например, следующее выражение вызовет ошибку." 66 | ], 67 | "cell_type": "markdown", 68 | "metadata": {} 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 2, 73 | "metadata": {}, 74 | "outputs": [ 75 | { 76 | "output_type": "error", 77 | "ename": "TypeError", 78 | "evalue": "unsupported operand type(s) for +: 'int' and 'str'", 79 | "traceback": [ 80 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 81 | "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", 82 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;36m1\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m'0'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 83 | "\u001b[1;31mTypeError\u001b[0m: unsupported operand type(s) for +: 'int' and 'str'" 84 | ] 85 | } 86 | ], 87 | "source": [ 88 | "1 + '0'" 89 | ] 90 | }, 91 | { 92 | "source": [ 93 | "Здесь не стоит ожидать автоматического преобразования ```1``` в строку или ```'0'``` в число. Необходимые преобразования типов нужно совершать явно с использованием соответствующих функций.\n", 94 | "\n", 95 | "Примерами языков со слабой типизацией является JavaScript." 96 | ], 97 | "cell_type": "markdown", 98 | "metadata": {} 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 3, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "output_type": "stream", 107 | "name": "stdout", 108 | "text": [ 109 | "10\n1\n" 110 | ] 111 | } 112 | ], 113 | "source": [ 114 | "print(str(1) + '0') # '10'\n", 115 | "print(1 + int('0')) # 1" 116 | ] 117 | }, 118 | { 119 | "source": [ 120 | "## Проверка типов\n", 121 | "\n", 122 | "В стандартной библиотеке Python есть функция ```type(obj)```, с помощью которой можно узнать тип объекта." 123 | ], 124 | "cell_type": "markdown", 125 | "metadata": {} 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 1, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "output_type": "stream", 134 | "name": "stdout", 135 | "text": [ 136 | "type(1) -> \ntype(\"abc\") -> \ntype(None) -> \ntype(print) -> \n" 137 | ] 138 | } 139 | ], 140 | "source": [ 141 | "print('type(1) -> ', type(1))\n", 142 | "print('type(\"abc\") -> ', type(\"abc\"))\n", 143 | "print('type(None) -> ', type(None))\n", 144 | "print('type(print) -> ', type(print))" 145 | ] 146 | }, 147 | { 148 | "source": [ 149 | "Проверить тип объекта можно с помощью оператора сравнения ```==``` или тождественности: ```is```, ```is not```. Тем не менее использование функции ```type``` и этих операторов не является правильным способом проверки типа объекта. " 150 | ], 151 | "cell_type": "markdown", 152 | "metadata": {} 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": 3, 157 | "metadata": {}, 158 | "outputs": [ 159 | { 160 | "output_type": "stream", 161 | "name": "stdout", 162 | "text": [ 163 | "1 is int (1) -> True\n1 is int (2) -> True\n" 164 | ] 165 | } 166 | ], 167 | "source": [ 168 | "print('1 is int (1) ->', type(1) == int) # Совсем не рекомендуется\n", 169 | "print('1 is int (2) ->', type(1) is int) # Не рекомендуется" 170 | ] 171 | }, 172 | { 173 | "source": [ 174 | "Для проверки типа объекта существует специальная функция ```isinstance```. Она принимает два аргумента. Первым аргументом должен быть проверяемый объект, а вторым тип объекта. В качестве предполагаемых типов можно указать несколько значений, тогда они указываются в скобках. В этом случае ```isinstance``` проверяет является ли тип объект одним из предполагаемых." 175 | ], 176 | "cell_type": "markdown", 177 | "metadata": {} 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": 5, 182 | "metadata": {}, 183 | "outputs": [ 184 | { 185 | "output_type": "stream", 186 | "name": "stdout", 187 | "text": [ 188 | "1 is int -> True\n1 is int or float -> True\n" 189 | ] 190 | } 191 | ], 192 | "source": [ 193 | "print('1 is int ->', isinstance(1, int))\n", 194 | "print('1 is int or float ->', isinstance(1, (int, float)))" 195 | ] 196 | }, 197 | { 198 | "source": [ 199 | "Из всех типов выделяется проверка на ```None```. Если необходимо узнать, находится ли в переменной это значение, то нужно использовать ```is```." 200 | ], 201 | "cell_type": "markdown", 202 | "metadata": {} 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 1, 207 | "metadata": {}, 208 | "outputs": [ 209 | { 210 | "output_type": "stream", 211 | "name": "stdout", 212 | "text": [ 213 | "== -> True\nis -> True\n" 214 | ] 215 | } 216 | ], 217 | "source": [ 218 | "foo = None\n", 219 | "print('== ->', foo == None) # Не по питоновски\n", 220 | "print('is ->', foo is None) # Правильно" 221 | ] 222 | } 223 | ] 224 | } -------------------------------------------------------------------------------- /python_pd/02_syntax/image/multiple_names.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/02_syntax/image/multiple_names.png -------------------------------------------------------------------------------- /python_pd/02_syntax/image/multiple_object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/02_syntax/image/multiple_object.png -------------------------------------------------------------------------------- /python_pd/02_syntax/image/name_object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/02_syntax/image/name_object.png -------------------------------------------------------------------------------- /python_pd/02_syntax/image/pyobject_int.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/02_syntax/image/pyobject_int.png -------------------------------------------------------------------------------- /python_pd/03_collections/00_overview.md: -------------------------------------------------------------------------------- 1 | # 3 Коллекции 2 | 3 | Здесь описаны основные коллекции и их возможности. Приводится описание 4 | двух полезных модулей стандартной библиотеки для работы с коллекциями: 5 | ```collections``` и ```itertools```. 6 | 7 | - [3.1 Базовые коллекции](basic_collections/00_overview.md) 8 | - [3.2 Изменяемые и неизменяемые типы данных](01_im_mutable_and_copy.ipynb) 9 | - [3.3 Включения](02_comprehensions.ipynb) 10 | - [3.4 Модуль ```collections```](03_collections.ipynb) 11 | - [3.5 Итераторы](04_iter.ipynb) 12 | - [3.6 Модуль ```itertools```](05_itertools.ipynb) 13 | 14 | [К содержанию](../../README.md) 15 | 16 | [4. Функции](../04_functions/00_overview.md) -------------------------------------------------------------------------------- /python_pd/03_collections/basic_collections/00_overview.md: -------------------------------------------------------------------------------- 1 | # 3.1 Базовые коллекции 2 | 3 | В этом разделе приводится описание базовых коллекций языка 4 | программирования Python: строк (```str```), списков (```list```), 5 | словарей (```dict```), кортежей (```tuple```), множеств (```set```). 6 | Рассматриваются операции с этими коллекциями и их преобразования друг 7 | в друга. Помимо этого, приводятся основные варианты применения этих 8 | коллекций. 9 | 10 | - [3.1.1 Строки](01_string.ipynb) 11 | - [3.1.2 Списки](02_list.ipynb) 12 | - [3.1.3 Словари](03_dict.ipynb) 13 | - [3.1.4 Кортежи](04_tuple.ipynb) 14 | - [3.1.5 Множества](05_set.ipynb) 15 | - [3.1.6 Преобразования коллекций](06_convert.ipynb) 16 | 17 | [К содержанию](../../../README.md) 18 | 19 | [3. Коллекции](../03_collections/00_overview.md) 20 | -------------------------------------------------------------------------------- /python_pd/03_collections/basic_collections/05_set.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Множества (```set```)\n", 8 | "\n", 9 | "Множества в Python полностью аналогичны одноименным математическим объектам. Множества -- это неупорядоченный набор уникальных элементов. В Python они представлены типом ```set```. Литералами множеств являются фигурные скобки, в точности как в математической нотации. Однако нельзя создать пустое множество с помощью выражения ```{}```, в этом случае будет создан пустой словарь. Пустое множество можно создать используя вызов функции ```set()```." 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "name": "stdout", 19 | "output_type": "stream", 20 | "text": [ 21 | "a = set(), type(a) = \n", 22 | "b = {1, 2, 3}, type(b) = \n" 23 | ] 24 | } 25 | ], 26 | "source": [ 27 | "a = set()\n", 28 | "b = {1, 2, 3}\n", 29 | "print(f'{a = }, {type(a) = }')\n", 30 | "print(f'{b = }, {type(b) = }')" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "Элементы множества должны быть хешируемыми, это означает, что в множествах можно хранить только неизменяемые типы. При этом само множество является изменяемым типом, а значит нехешируемо. Обратите внимание, что кортежи являются хешируемыми, только в том случае, если все их элементы хешируемы. В примере ниже в запись множества были добавлены элементы ```1``` и ```True```, которые являются эквивалентными. Поэтому при создании множества объект ```True``` был исключен как дубликат." 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 2, 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "name": "stdout", 47 | "output_type": "stream", 48 | "text": [ 49 | "a = {False, 1, 2.0, (1, 2, 3), None, (3+4j), , 'monty_python'}\n" 50 | ] 51 | } 52 | ], 53 | "source": [ 54 | "a = {\n", 55 | " 1, 2.0, 3 + 4j,\n", 56 | " 'monty_python',\n", 57 | " True, False, None,\n", 58 | " (1, 2, 3),\n", 59 | " tuple,\n", 60 | "}\n", 61 | "print(f'{a = }')" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "Такое поведение делает из множеств отличный инструмент для удаления дубликатов (поиск уникальных элементов) из последовательностей." 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 3, 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "name": "stdout", 78 | "output_type": "stream", 79 | "text": [ 80 | "set(a) = {3, 1, 42, 2}\n" 81 | ] 82 | } 83 | ], 84 | "source": [ 85 | "a = [42, 1, 2, 1, 3, 1, 2]\n", 86 | "print(f'{set(a) = }')" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "## Операции со множествами\n", 94 | "\n", 95 | "Можно узнать длину множества с помощью стандартной функции ```len```." 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 4, 101 | "metadata": {}, 102 | "outputs": [ 103 | { 104 | "name": "stdout", 105 | "output_type": "stream", 106 | "text": [ 107 | "len(a) = 3\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "a = {1, 2, 3}\n", 113 | "print(f'{len(a) = }')" 114 | ] 115 | }, 116 | { 117 | "cell_type": "markdown", 118 | "metadata": {}, 119 | "source": [ 120 | "Множества в Python реализованы на основе хэш-таблиц. В связи с этим множества являются неупорядоченными коллекциями. Это приводит к тому, что во множествах нельзя обращаться к элементу по индексу и нельзя брать срез. " 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 5, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "name": "stdout", 130 | "output_type": "stream", 131 | "text": [ 132 | "b = {0, 3, 42, '0', -1, 'abc'}\n" 133 | ] 134 | }, 135 | { 136 | "ename": "TypeError", 137 | "evalue": "'set' object is not subscriptable", 138 | "output_type": "error", 139 | "traceback": [ 140 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 141 | "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", 142 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mb\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m{\u001b[0m\u001b[1;36m3\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m42\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'abc'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m-\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'0'\u001b[0m\u001b[1;33m}\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mf'{b = }'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mf'{b[0] = }'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 143 | "\u001b[1;31mTypeError\u001b[0m: 'set' object is not subscriptable" 144 | ] 145 | } 146 | ], 147 | "source": [ 148 | "b = {3, 42, 'abc', 0, -1, '0'}\n", 149 | "print(f'{b = }')\n", 150 | "print(f'{b[0] = }')" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": {}, 156 | "source": [ 157 | "Однако, множества являются итерируемыми коллекциями. Но не стоит итерироваться по ним из-за отсутствия порядка. " 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 6, 163 | "metadata": {}, 164 | "outputs": [ 165 | { 166 | "name": "stdout", 167 | "output_type": "stream", 168 | "text": [ 169 | "0\n", 170 | "42\n", 171 | "3\n", 172 | "abc\n" 173 | ] 174 | } 175 | ], 176 | "source": [ 177 | "b = {3, 42, 'abc', 0}\n", 178 | "\n", 179 | "for item in b:\n", 180 | " print(f'{item}')" 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "metadata": {}, 186 | "source": [ 187 | "Со множествами можно выполнять все операции, предусмотренные теорией множеств, а именно брать пересечение, объединение, разность и др. Эти операции представлены несколькими способами. Можно использовать операторы ```&```, ```|```, ```-``` и другие. В этом случае оба операнда должны иметь тип ```set```. Для всех этих операций есть представление в виде соответствующих методов. Отличие операторов от методов заключается в том, что методы могут принимать не только аргументы, которые должны иметь тип ```set```, но и любой итерируемый объект. Кроме этого методы могут принимать любое количество аргументов. Дополнительно у этих операторов есть аналоги в виде in-line операторов и соответствующие методы для изменения множеств \"на месте\"." 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": 7, 193 | "metadata": {}, 194 | "outputs": [ 195 | { 196 | "name": "stdout", 197 | "output_type": "stream", 198 | "text": [ 199 | "Пересечение: a & b = {3, 4}\n", 200 | "Пересечение: a.intersection(b) = {3, 4}\n", 201 | "Разность: a - b = {1, 2}\n", 202 | "Пересечение (in-place): a = {3, 4}\n" 203 | ] 204 | } 205 | ], 206 | "source": [ 207 | "a = {1, 2, 3, 4}\n", 208 | "b = {3, 4, 5, 6}\n", 209 | "\n", 210 | "print(f'Пересечение: {a & b = }') # a и b должны быть типа set\n", 211 | "# a должна быть типа set, b любой итерируемый объект, может \n", 212 | "# принимать любое количество аргументов.\n", 213 | "print(f'Пересечение: {a.intersection(b) = }')\n", 214 | "print(f'Разность: {a - b = }')\n", 215 | "\n", 216 | "a &= b\n", 217 | "print(f'Пересечение (in-place): {a = }')" 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "metadata": {}, 223 | "source": [ 224 | "В таблице приведены операторы и методы для этих операций.\n", 225 | "\n", 226 | "| Операция | Оператор | Метод |\n", 227 | "|-------------------------|:--------:|-----------------------------------|\n", 228 | "| Пересечение | ```&``` | ```intersection``` |\n", 229 | "| | ```&=``` | ```intersection_update``` |\n", 230 | "| Объединение | ```\\|``` | ```union``` |\n", 231 | "| | `\\|=` | ```update``` |\n", 232 | "| Разность | ```-``` | ```difference``` |\n", 233 | "| | ```-=``` | ```difference_update``` |\n", 234 | "| Симметрическая разность | ```^``` | ```symmetric_difference``` |\n", 235 | "| | ```^=``` | ```symmetric_difference_update``` |\n", 236 | "\n", 237 | "Кроме этих математический операций существует набор операций сравнения, включая оператор ```in``` для проверки элемента на вхождение в множество." 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": 8, 243 | "metadata": {}, 244 | "outputs": [ 245 | { 246 | "name": "stdout", 247 | "output_type": "stream", 248 | "text": [ 249 | "Проверка наличия элемента: 1 in a = True\n", 250 | "b влючено в a (подмножество): b <= a = True\n", 251 | "b строго влючено в a (подмножество): b < a = True\n", 252 | "b включает a (надмножество): b >= a = False\n", 253 | "b строго включает a (надмножество): b > a = False\n" 254 | ] 255 | } 256 | ], 257 | "source": [ 258 | "a = {1, 2, 3, 4}\n", 259 | "b = {3, 4}\n", 260 | "\n", 261 | "print(f'Проверка наличия элемента: {1 in a = }')\n", 262 | "print(f'b влючено в a (подмножество): {b <= a = }')\n", 263 | "print(f'b строго влючено в a (подмножество): {b < a = }')\n", 264 | "print(f'b включает a (надмножество): {b >= a = }')\n", 265 | "print(f'b строго включает a (надмножество): {b > a = }')" 266 | ] 267 | }, 268 | { 269 | "cell_type": "markdown", 270 | "metadata": {}, 271 | "source": [ 272 | "Так как множества -- это изменяемый тип, то для них есть набор методов для их изменения." 273 | ] 274 | }, 275 | { 276 | "cell_type": "code", 277 | "execution_count": 9, 278 | "metadata": {}, 279 | "outputs": [], 280 | "source": [ 281 | "a = {1, 2, 3, 4}\n", 282 | "a.add(5) # добавить элемент\n", 283 | "b = a.pop() # удалить элемент\n", 284 | "a.remove(2) # удалить элемент по значению\n", 285 | "a.discard(5) # удалить элемент по значению, если есть" 286 | ] 287 | }, 288 | { 289 | "cell_type": "markdown", 290 | "metadata": {}, 291 | "source": [ 292 | "# Полезные ссылки\n", 293 | "\n", 294 | "- [Python и теория множеств](https://habr.com/ru/post/516858/#otnosheniya-mezhdu-mnozhestvami)" 295 | ] 296 | } 297 | ], 298 | "metadata": { 299 | "interpreter": { 300 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 301 | }, 302 | "kernelspec": { 303 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)", 304 | "name": "python3" 305 | }, 306 | "language_info": { 307 | "codemirror_mode": { 308 | "name": "ipython", 309 | "version": 3 310 | }, 311 | "file_extension": ".py", 312 | "mimetype": "text/x-python", 313 | "name": "python", 314 | "nbconvert_exporter": "python", 315 | "pygments_lexer": "ipython3", 316 | "version": "3.9.0" 317 | }, 318 | "orig_nbformat": 2 319 | }, 320 | "nbformat": 4, 321 | "nbformat_minor": 2 322 | } 323 | -------------------------------------------------------------------------------- /python_pd/03_collections/image/array_shift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/array_shift.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/comprehensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/comprehensions.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/copy.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/copy_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/copy_2.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/copy_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/copy_3.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/deque.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/deque.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/dict.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/dict.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/dragon_curve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/dragon_curve.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/gen_iter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/gen_iter.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/graph.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/immutable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/immutable.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/index.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/index.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/prefix_suffix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/prefix_suffix.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/stack.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/tuple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/tuple.png -------------------------------------------------------------------------------- /python_pd/03_collections/image/tuple_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/03_collections/image/tuple_2.png -------------------------------------------------------------------------------- /python_pd/04_functions/00_overview.md: -------------------------------------------------------------------------------- 1 | # 4. Функции 2 | 3 | В этом модуле подробно описаны возможности функций и исключений Python. 4 | Рассматриваются такие полезные инструменты как замыкания, декораторы и 5 | генераторы. 6 | 7 | - [4.1 Аргументы](01_args.ipynb) 8 | - [4.2 Возвращаемые значения](02_return.ipynb) 9 | - [4.3 Анонимные функции](03_lambda.ipynb) 10 | - [4.4 Области видимости](04_legb.ipynb) 11 | - [4.5 Рекурсия](05_recursion.ipynb) 12 | - [4.6 Замыкания](06_closures.ipynb) 13 | - [4.7 Декораторы](07_decorators.ipynb) 14 | - [4.8 Генераторы](08_generators.ipynb) 15 | - [4.9 Модуль ```functools```](09_functools.ipynb) 16 | - [4.10 Исключения](10_exceptions.ipynb) 17 | 18 | [К содержанию](../../README.md) 19 | 20 | [5. Файлы](../05_files/00_overview.md) 21 | -------------------------------------------------------------------------------- /python_pd/04_functions/02_return.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Оператор ```return```\n", 27 | "\n", 28 | "Для того, чтобы вернуть что-либо из функции необходимо использовать оператор ```return```. Для того, чтобы вернуть значение достаточно указать его сразу после ```return```. Несмотря на это он является не обязательным. В Python функции **всегда** возвращают результат, вне зависимости от наличия ```return```. в случает отсутствия ```return``` функция вернет ```None```. Отсутствие ```return``` эквивалентно ```return None```, поэтому последнее можно опускать. Еще одной эквивалентной конструкцией является указание просто ```return``` без аргумента. В этом случае также будет возвращено ```None```." 29 | ], 30 | "cell_type": "markdown", 31 | "metadata": {} 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 1, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "output_type": "stream", 40 | "name": "stdout", 41 | "text": [ 42 | "foo() = 42\nbar() = None\nbaz() = None\nquz() = None\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "def foo():\n", 48 | " \"\"\"Функция возвращает одно значение\"\"\"\n", 49 | " return 42\n", 50 | "\n", 51 | "print(f'{foo() = }')\n", 52 | "\n", 53 | "def bar():\n", 54 | " \"\"\"Функция возвращает None\"\"\"\n", 55 | " return None\n", 56 | "\n", 57 | "def baz():\n", 58 | " \"\"\"Функция возвращает None\"\"\"\n", 59 | " return\n", 60 | "\n", 61 | "def quz():\n", 62 | " \"\"\"Функция возвращает None\"\"\"\n", 63 | " pass\n", 64 | "\n", 65 | "print(f'{bar() = }')\n", 66 | "print(f'{baz() = }')\n", 67 | "print(f'{quz() = }')" 68 | ] 69 | }, 70 | { 71 | "source": [ 72 | "Из функции можно вернуть сразу несколько значений. Для этого достаточно после ```return``` указать несколько значений через запятую. На самом деле в этом случае будет возвращено одно значение - кортеж, состоящий из указанных значений." 73 | ], 74 | "cell_type": "markdown", 75 | "metadata": {} 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 2, 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "output_type": "stream", 84 | "name": "stdout", 85 | "text": [ 86 | "foo() = (1, 2, 3)\ntype(foo()) = \n" 87 | ] 88 | } 89 | ], 90 | "source": [ 91 | "def foo():\n", 92 | " return 1, 2, 3\n", 93 | "\n", 94 | "print(f'{foo() = }')\n", 95 | "print(f'{type(foo()) = }')" 96 | ] 97 | }, 98 | { 99 | "source": [ 100 | "Результат, возвращаемый из функции, можно связать с именем с помощью знака ```=````. Слева от него должен находиться идентификатор, а слева вызов функции. Если функция возвращает несколько значений, то можно использовать распаковку значений, по аналогии с распаковкой коллекций." 101 | ], 102 | "cell_type": "markdown", 103 | "metadata": {} 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 3, 108 | "metadata": {}, 109 | "outputs": [ 110 | { 111 | "output_type": "stream", 112 | "name": "stdout", 113 | "text": [ 114 | "a = 1, b = (1, 2, 3)\nc = 1, d = 2, e = 3\n" 115 | ] 116 | } 117 | ], 118 | "source": [ 119 | "def spam():\n", 120 | " return 1\n", 121 | "\n", 122 | "def eggs():\n", 123 | " return 1, 2, 3\n", 124 | "\n", 125 | "# связывание результата функции с новым именем\n", 126 | "a = spam()\n", 127 | "b = eggs()\n", 128 | "\n", 129 | "# распаковка результата фкнции\n", 130 | "c, d, e = eggs()\n", 131 | "\n", 132 | "print(f'{a = }, {b = }')\n", 133 | "print(f'{c = }, {d = }, {e = }')" 134 | ] 135 | }, 136 | { 137 | "source": [ 138 | "Некоторые встроенные функции \"не возвращают\" результат, например, функция вывода ```print```. В качестве результата выступает ```None```. Поэтому будет полностью логично связать ее результат с именем." 139 | ], 140 | "cell_type": "markdown", 141 | "metadata": {} 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 4, 146 | "metadata": {}, 147 | "outputs": [ 148 | { 149 | "output_type": "stream", 150 | "name": "stdout", 151 | "text": [ 152 | "Ничего\na = None\n" 153 | ] 154 | } 155 | ], 156 | "source": [ 157 | "a = print('Ничего')\n", 158 | "print(f'{a = }')" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": null, 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [] 167 | } 168 | ] 169 | } -------------------------------------------------------------------------------- /python_pd/04_functions/05_recursion.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Рекурсия\n", 27 | "\n", 28 | "Рекурсия -- это вызов функции из неё же самой, непосредственно (простая рекурсия) или через другие функции (сложная или косвенная рекурсия). Это довольно распространенный инструмент для решения разных задач. В основном его удобно использовать в тех случаях, когда решение исходной задачи можно получить, используя решение этой же, но более маленькой задачи. Ярким примером рекурсии являются числовые последовательности, описываемые рекуррентными формулами, например, числа Фибоначчи, факториал и др." 29 | ], 30 | "cell_type": "markdown", 31 | "metadata": {} 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 1, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "output_type": "stream", 40 | "name": "stdout", 41 | "text": [ 42 | "fib(0) = 1\nfib(1) = 1\nfib(2) = 2\nfib(3) = 3\nfib(4) = 5\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "def fib(n):\n", 48 | " if n in (0, 1):\n", 49 | " return 1\n", 50 | " return fib(n - 1) + fib(n - 2)\n", 51 | "\n", 52 | "\n", 53 | "for i in range(5):\n", 54 | " print(f'fib({i}) = {fib(i)}')" 55 | ] 56 | }, 57 | { 58 | "source": [ 59 | "Рекурсия обладает существенными недостатками. Например, для ее реализации в большинстве случаев используется стек, т.е. состояния каждого вызова функции, включая локальные переменные, будет сохранено в памяти. Таких вызовов может быть достаточно много, что может привести к переполнению. В Python установлено ограничение на глубину стека равную 1000 (это значение может отличаться), при ее превышении будет возбуждено исключение ```RecursionError```. Кроме этого, рекурсия выполняется довольно долго.\n", 60 | "\n", 61 | "Самостоятельно запустите этот код на [pythontutor](http://www.pythontutor.com/visualize.html#code=def%20fib%28n%29%3A%0A%20%20%20%20if%20n%20in%20%280,%201%29%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20fib%28n%20-%201%29%20%2B%20fib%28n%20-%202%29%0A%0Aprint%28fib%284%29%29&cumulative=false&curInstr=0&heapPrimitives=true&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) и пронаблюдайте, что происходит в памяти в момент выполнения.\n", 62 | "\n", 63 | "Проверить ограничение на количество вызовов рекурсивных функций можно с помощью модуля ```sys```." 64 | ], 65 | "cell_type": "markdown", 66 | "metadata": {} 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 2, 71 | "metadata": {}, 72 | "outputs": [ 73 | { 74 | "output_type": "execute_result", 75 | "data": { 76 | "text/plain": [ 77 | "3000" 78 | ] 79 | }, 80 | "metadata": {}, 81 | "execution_count": 2 82 | } 83 | ], 84 | "source": [ 85 | "import sys\n", 86 | "sys.getrecursionlimit()" 87 | ] 88 | }, 89 | { 90 | "source": [ 91 | "Иногда рекурсия бывает далеко не оптимальна. Например, в вычислении чисел Фибоначчи функция ```fib``` будет несколько раз вычислять одинаковые значения. Для этой функции легко построить граф, например, для вычисления 5-го числа Фибоначчи.\n", 92 | "\n", 93 | "\n", 94 | "\n", 95 | "Здесь видно, что третье число будет вычислено 2 раза, второе - 3 раза и т.д.\n", 96 | "\n", 97 | "Исправить такой недостаток рекурсии можно воспользовавшись [динамическим программированием](https://en.wikipedia.org/wiki/Dynamic_programming). Основу этого подхода составляет разбиение задач на более простые и решение их по отдельности. Затем решения подзадач объединяются в решение исходной задачи. Ключевым моментом выступает то, что каждая подзадача решается ровно один раз.\n", 98 | "\n", 99 | "Далее приведен пример вычисления чисел Фибоначчи с использованием динамического программирования." 100 | ], 101 | "cell_type": "markdown", 102 | "metadata": {} 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 3, 107 | "metadata": {}, 108 | "outputs": [ 109 | { 110 | "output_type": "stream", 111 | "name": "stdout", 112 | "text": [ 113 | "fib(0) = 1\nfib(1) = 1\nfib(2) = 2\nfib(3) = 3\nfib(4) = 5\n" 114 | ] 115 | } 116 | ], 117 | "source": [ 118 | "def fib(n):\n", 119 | " numbers = [1, 1]\n", 120 | " for i in range(1, n):\n", 121 | " numbers.append(numbers[-1] + numbers[-2])\n", 122 | " return numbers[-1]\n", 123 | "\n", 124 | "\n", 125 | "for i in range(5):\n", 126 | " print(f'fib({i}) = {fib(i)}')" 127 | ] 128 | }, 129 | { 130 | "source": [ 131 | "Таким образом, везде, где есть возможность решить задачу без применения рекурсии, лучше решать ее без использования рекурсии." 132 | ], 133 | "cell_type": "markdown", 134 | "metadata": {} 135 | }, 136 | { 137 | "source": [ 138 | "# Полезные ссылки\n", 139 | "\n", 140 | "- [Рекурсия (вики)](https://en.wikipedia.org/wiki/Recursion)\n", 141 | "- [Thinking Recursively in Python](https://realpython.com/python-thinking-recursively/)" 142 | ], 143 | "cell_type": "markdown", 144 | "metadata": {} 145 | } 146 | ] 147 | } -------------------------------------------------------------------------------- /python_pd/04_functions/06_closures.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Замыкания\n", 27 | "\n", 28 | "Возможность использования вложенными функциями переменных из внешних областей видимости существенно расширяет возможности применения функций. В частности, применение замыканий. В обще смысле замыкание — это функция, в теле которой присутствуют ссылки на переменные, объявленные вне тела этой функции в окружающем коде и не являющиеся ее параметрами. Например, фабрика функций поиска минимума в заранее заданном интервале:" 29 | ], 30 | "cell_type": "markdown", 31 | "metadata": {} 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 1, 36 | "metadata": {}, 37 | "outputs": [ 38 | { 39 | "output_type": "stream", 40 | "name": "stdout", 41 | "text": [ 42 | "1\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "def make_min(*, l, h):\n", 48 | " def inner(a, b, *args):\n", 49 | " args = (a, b) + args\n", 50 | " return min(i for i in args if l <= i <= h)\n", 51 | " return inner\n", 52 | "\n", 53 | "bounded_min = make_min(l=0, h=42)\n", 54 | "print(f'{bounded_min(*[-1, 4, 254, 42, 1])}')" 55 | ] 56 | }, 57 | { 58 | "source": [ 59 | "Здесь при вызове функции ```bounded_min``` фактически происходит вызов ```inner```, находящейся внутри ```make_min```. При этом переменные ```l``` и ```h``` не уничтожаются сборщиком мусора, так как на них все еще остаются ссылки из вложенной функции ```inner```.\n", 60 | "\n", 61 | "Дело в том, что ссылки такие объекты сохраняются в специальном атрибуте объекта функций. Его можно получить используя ```__closure__```. Элементы, хранящиеся в этом кортеже, имеют тип ```cell```. Это специальный тип в Python, предназначенный для внутреннего использования. У элементов кортежа ```__closure__``` есть атрибут ```cell_contents``` с помощью которого можно получить объект." 62 | ], 63 | "cell_type": "markdown", 64 | "metadata": {} 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": 10, 69 | "metadata": {}, 70 | "outputs": [ 71 | { 72 | "output_type": "stream", 73 | "name": "stdout", 74 | "text": [ 75 | "bounded_min.__closure__ = (, )\ntype(bounded_min.__closure__[0]) = \nbounded_min.__closure__[0].cell_contents = 42\nbounded_min.__closure__[1].cell_contents = 0\n" 76 | ] 77 | } 78 | ], 79 | "source": [ 80 | "print(f'{bounded_min.__closure__ = }')\n", 81 | "print(f'{type(bounded_min.__closure__[0]) = }')\n", 82 | "\n", 83 | "print(f'{bounded_min.__closure__[0].cell_contents = }')\n", 84 | "print(f'{bounded_min.__closure__[1].cell_contents = }')" 85 | ] 86 | }, 87 | { 88 | "source": [ 89 | "Выполните этот код в [pythontutor](http://www.pythontutor.com/visualize.html#code=def%20make_min%28*,%20l,%20h%29%3A%0A%20%20%20%20def%20inner%28a,%20b,%20*args%29%3A%0A%20%20%20%20%20%20%20%20args%20%3D%20%28a,%20b%29%20%2B%20args%0A%20%20%20%20%20%20%20%20return%20min%28i%20for%20i%20in%20args%20if%20l%20%3C%3D%20i%20%3C%3D%20h%29%0A%20%20%20%20return%20inner%0A%0Abounded_min%20%3D%20make_min%28l%3D0,%20h%3D42%29%0Ares%20%3D%20bounded_min%28*%5B-1,%204,%20254,%2042,%201%5D%29%0Aprint%28res%29&cumulative=false&curInstr=0&heapPrimitives=true&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) и посмотрите, что происходит в памяти в момент выполнения.\n", 90 | "\n", 91 | "Переменные можно использовать не только из объемлющей области видимости." 92 | ], 93 | "cell_type": "markdown", 94 | "metadata": {} 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 12, 99 | "metadata": {}, 100 | "outputs": [ 101 | { 102 | "output_type": "stream", 103 | "name": "stdout", 104 | "text": [ 105 | "0\n1\n2\n3\n" 106 | ] 107 | } 108 | ], 109 | "source": [ 110 | "def foo(): # плохая практика\n", 111 | " print(i)\n", 112 | "\n", 113 | "for i in range(4):\n", 114 | " foo()" 115 | ] 116 | }, 117 | { 118 | "source": [ 119 | "## Позднее связывание\n", 120 | "\n", 121 | "Рассмотрим случай, когда необходимо создать несколько функций." 122 | ], 123 | "cell_type": "markdown", 124 | "metadata": {} 125 | }, 126 | { 127 | "cell_type": "code", 128 | "execution_count": 14, 129 | "metadata": {}, 130 | "outputs": [ 131 | { 132 | "output_type": "stream", 133 | "name": "stdout", 134 | "text": [ 135 | "10\n10\n10\n" 136 | ] 137 | } 138 | ], 139 | "source": [ 140 | "def create_multipiers():\n", 141 | " return [lambda x: i * x for i in range(3)]\n", 142 | "\n", 143 | "for multiplier in create_multipiers():\n", 144 | " print(multiplier(5))" 145 | ] 146 | }, 147 | { 148 | "source": [ 149 | "Выполните этот код в [pythontutor](http://www.pythontutor.com/visualize.html#code=def%20create_multipiers%28%29%3A%0A%20%20%20%20return%20%5Blambda%20x%3A%20i%20*%20x%20for%20i%20in%20range%283%29%5D%0A%0Afor%20multiplier%20in%20create_multipiers%28%29%3A%0A%20%20%20%20print%28multiplier%285%29%29&cumulative=false&curInstr=0&heapPrimitives=true&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) и посмотрите, что происходит в памяти в момент выполнения.\n", 150 | "\n", 151 | "Результат отличается от ожидаемого. Это происходит из-за поздней привязки в Python, которое заключается в том, что поиск значений переменных, используемых в замыканиях, происходит во время вызова внутренней функции. Таким образом, в приведенном выше коде всякий раз, когда вызывается какая-либо из возвращаемых функций (т.е. ```multiplier```), значение ```i``` ищется в окружающей области видимости во время ее вызова (а к тому времени цикл уже завершился, поэтому ```i``` уже был присвоен конечный результат — значение ```2```).\n", 152 | "\n", 153 | "Для решения этой проблемы достаточно явно передать в каждое замыкание (т.е. лямбду) переменную ```i``` используя именованные аргументы." 154 | ], 155 | "cell_type": "markdown", 156 | "metadata": {} 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 15, 161 | "metadata": {}, 162 | "outputs": [ 163 | { 164 | "output_type": "stream", 165 | "name": "stdout", 166 | "text": [ 167 | "0\n5\n10\n" 168 | ] 169 | } 170 | ], 171 | "source": [ 172 | "def create_multipiers():\n", 173 | " return [lambda x, i=i: i * x for i in range(3)]\n", 174 | "\n", 175 | "for multiplier in create_multipiers():\n", 176 | " print(multiplier(5))" 177 | ] 178 | }, 179 | { 180 | "source": [ 181 | "# Полезные ссылки\n", 182 | "\n", 183 | "- [Python Inner Functions—What Are They Good For?](https://realpython.com/inner-functions-what-are-they-good-for/)\n", 184 | "- [Why aren't python nested functions called closures?](https://stackoverflow.com/questions/4020419/why-arent-python-nested-functions-called-closures)" 185 | ], 186 | "cell_type": "markdown", 187 | "metadata": {} 188 | } 189 | ] 190 | } -------------------------------------------------------------------------------- /python_pd/04_functions/09_functools.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Модуль ```functools```\n", 27 | "\n", 28 | "Модуль ```functools``` содержит большое количество декораторов и функций для разных задачь. Туда включены: \n", 29 | "- декораторы для кеширования результатов функций (```cache```, ```lru_cache``` и др.);\n", 30 | "- декораторы для облегчения написания декораторов и классов(```wraps```, ```total_ordering```);\n", 31 | "- декораторы для сокращения количества передаваемых аргументов (```partial```);\n", 32 | "- и другие.\n", 33 | "\n", 34 | "Рассмотрим некоторые из них.\n", 35 | "\n", 36 | "Декоратор ```lru_cache(maxsize=128, typed=False)``` предназначен для [LRU кеширования](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)). Это означает, что он \"запоминает\" результаты и аргументы вызова функций, и, когда функция повторно вызывается с такими же аргументами, то результат не вычисляется, а возвращается сохраненное значение. Это очень удобно, если функция выполняет тяжеловесные вычисления. \n", 37 | "\n", 38 | "```lru_cache``` использует в качестве кэша словарь, поэтому все аргументы должны быть хешируемыми.\n", 39 | "\n", 40 | "Аргумент ```maxsize``` определяет размер памяти, ```lru_cache``` удаляет из кеша слишком старые результаты, тем самым экономя память. Если ```maxsize``` установлен в ```None```, кэш может возрастать бесконечно. Также функция наиболее эффективна, если ```maxsize``` это степень двойки.\n", 41 | "\n", 42 | "Декоратор ```lru_cache``` может учитывать типы аргументов, для этого используется аргумент ```typed```. Если он установлен в ```True```, аргументы функции с разными типами будут кэшироваться отдельно. Например, ```f(3)``` и ```f(3.0)``` будут считаться разными вызовами, возвращающие, возможно, различный результат.\n", 43 | "\n", 44 | "Чтобы помочь измерить эффективность кэширования и отрегулировать размер кэша, обёрнутая функция дополняется функцией ```cache_info()```, возвращающая ```namedtuple```, показывающий попадания в кэш, промахи, максимальный размер и текущий размер. В многопоточном окружении, количество попаданий и промахов будет приблизительным.\n", 45 | "\n", 46 | "Также имеется функция ```cache_clear()``` для очистки кэша.\n", 47 | "\n", 48 | "Оригинальная функция доступна через атрибут ```__wrapped__```." 49 | ], 50 | "cell_type": "markdown", 51 | "metadata": {} 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 4, 56 | "metadata": {}, 57 | "outputs": [ 58 | { 59 | "output_type": "stream", 60 | "name": "stdout", 61 | "text": [ 62 | "factorial(5) = 120\nfactorial(10) = 3628800\nfactorial(100) = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000\nfactorial(6) = 720\nfactorial(100) = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000\nfactorial(5) = 120\n--------------------------------------------------\nCacheInfo(hits=3, misses=208, maxsize=5, currsize=5)\n" 63 | ] 64 | } 65 | ], 66 | "source": [ 67 | "from functools import lru_cache\n", 68 | "\n", 69 | "@lru_cache(maxsize=5)\n", 70 | "def factorial(n):\n", 71 | " if n == 0:\n", 72 | " return 1\n", 73 | " return n * factorial(n - 1)\n", 74 | "\n", 75 | "\n", 76 | "print(f'{factorial(5) = }')\n", 77 | "print(f'{factorial(10) = }')\n", 78 | "print(f'{factorial(100) = }')\n", 79 | "print(f'{factorial(6) = }')\n", 80 | "print(f'{factorial(100) = }')\n", 81 | "print(f'{factorial(5) = }')\n", 82 | "print('-' * 50)\n", 83 | "\n", 84 | "print(f'{factorial.cache_info()}')" 85 | ] 86 | }, 87 | { 88 | "source": [ 89 | "Декоратор ```partial(func, *args, **keywords)``` используется для частичного определения аргументов функции до ее непосредственного вызова. В момент вызова декорируемой функции ```func```, помимо явно передаваемых аргументов, будут переданы аргументы из ```args``` и ```keywords``` декоратора ```partial```." 90 | ], 91 | "cell_type": "markdown", 92 | "metadata": {} 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 16, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "output_type": "stream", 101 | "name": "stdout", 102 | "text": [ 103 | "min_5 = functools.partial(, 5)\ntype(min_5) = \nmin_5(10, 2) = 2\nmin_5(10) = 5\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "from functools import partial\n", 109 | "\n", 110 | "min_5 = partial(min, 5)\n", 111 | "print(f'{min_5 = }')\n", 112 | "print(f'{type(min_5) = }')\n", 113 | "\n", 114 | "print(f'{min_5(10, 2) = }')\n", 115 | "print(f'{min_5(10) = }')" 116 | ] 117 | }, 118 | { 119 | "source": [ 120 | "Это будет эквивалентно" 121 | ], 122 | "cell_type": "markdown", 123 | "metadata": {} 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": null, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "sum_5 = lambda *args: min(5, *args)" 132 | ] 133 | }, 134 | { 135 | "source": [ 136 | "В других языках программирования можно создать несколько функций с одним названием, но с разными типами аргументов.\n", 137 | "\n", 138 | "Как проделать тоже самое только в Python? Конечно, вы можете вручную проверять типы аргументов, но это не всегда бывает удобно. В модуле ```functools``` есть декоратор ```singledispatch```, который позволяет реализовать этот функционал.\n", 139 | "\n", 140 | "Реализуем аналог функции ```range``` в нескольких вариантах исполнения: для целых чисел и для чисел с плавающей точкой.\n", 141 | "\n", 142 | "Декоратором ```singledispatch``` декорируется базовая функция, она будет использоваться, если никакие остальные реализации не подходят.\n", 143 | "\n", 144 | "С помощью метода ```register``` отмечаются остальные реализации. Он может принимать тип, для которого эта реализация будет использоваться. \n", 145 | "\n", 146 | "У этого подхода есть один недостаток. Предполагается, что у всех позиционных аргументов тип одинаковый.\n", 147 | "\n", 148 | "Подробное описание и большое количество примеров см. в [документации](https://docs.python.org/3/library/functools.html)." 149 | ], 150 | "cell_type": "markdown", 151 | "metadata": {} 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 30, 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "output_type": "stream", 160 | "name": "stdout", 161 | "text": [ 162 | "1\n2\n-------------------------\n1.0\n1.5\n2.0\n2.5\n-------------------------\nbase func\n" 163 | ] 164 | } 165 | ], 166 | "source": [ 167 | "from functools import singledispatch\n", 168 | "\n", 169 | "@singledispatch\n", 170 | "def my_range(start, stop, step):\n", 171 | " print('base func')\n", 172 | "\n", 173 | "@my_range.register(int)\n", 174 | "def _(start, stop, step):\n", 175 | " for i in range(start, stop, step):\n", 176 | " print(i)\n", 177 | "\n", 178 | "@my_range.register(float)\n", 179 | "def _(start, stop, step):\n", 180 | " while start < stop:\n", 181 | " print(start)\n", 182 | " start += step\n", 183 | "\n", 184 | "\n", 185 | "my_range(1, 3, 1)\n", 186 | "print('-' * 25)\n", 187 | "my_range(1., 3., 0.5)\n", 188 | "print('-' * 25)\n", 189 | "my_range('a', 'b', 'c')" 190 | ] 191 | }, 192 | { 193 | "source": [ 194 | "Функция ```update_wrapper``` и ее аналог декоратор ```wraps``` нужны для копирования служебной информации присоздании собственных декораторов: имени функции, документации и другого." 195 | ], 196 | "cell_type": "markdown", 197 | "metadata": {} 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": 1, 202 | "metadata": {}, 203 | "outputs": [ 204 | { 205 | "output_type": "stream", 206 | "name": "stdout", 207 | "text": [ 208 | "bar\nБесполезная функция\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "from functools import wraps\n", 214 | "\n", 215 | "def foo(f):\n", 216 | " @wraps(f)\n", 217 | " def inner():\n", 218 | " print(f'{f.__name__}')\n", 219 | " f()\n", 220 | " return inner\n", 221 | "\n", 222 | "@foo\n", 223 | "def bar():\n", 224 | " \"\"\"Бесполезная функция\"\"\"\n", 225 | " print('(-‸ლ)')\n", 226 | "\n", 227 | "print(f'{bar.__name__}')\n", 228 | "print(f'{bar.__doc__}')" 229 | ] 230 | }, 231 | { 232 | "source": [ 233 | "Декоратор ```total_ordering``` очень полезен при работе с классами. Он позволяет автоматически реализовывать все виды операторов сравнения. Для этого достаточно, чтобы класс реализовал только два метода: метод сравнения на равенство ```__eq__``` и один из методов ```__lt__```, ```__le__```, ```__gt__```, или ```__ge__```. Это существенно упрощает работу." 234 | ], 235 | "cell_type": "markdown", 236 | "metadata": {} 237 | }, 238 | { 239 | "source": [ 240 | "# Полезные ссылки\n", 241 | "\n", 242 | "- [Документация](https://docs.python.org/3/library/functools.html)\n", 243 | "- [PEP 443 -- Single-dispatch generic functions](https://www.python.org/dev/peps/pep-0443/)" 244 | ], 245 | "cell_type": "markdown", 246 | "metadata": {} 247 | } 248 | ] 249 | } -------------------------------------------------------------------------------- /python_pd/04_functions/image/dv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/04_functions/image/dv.png -------------------------------------------------------------------------------- /python_pd/04_functions/image/enclosing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/04_functions/image/enclosing.png -------------------------------------------------------------------------------- /python_pd/04_functions/image/fib_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/04_functions/image/fib_graph.png -------------------------------------------------------------------------------- /python_pd/04_functions/image/legb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/04_functions/image/legb.png -------------------------------------------------------------------------------- /python_pd/05_files/00_overview.md: -------------------------------------------------------------------------------- 1 | # 5. Файлы 2 | 3 | Раздел посвящен работе с текстовыми и бинарными файлами. Рассматриваются 4 | такие модули стандартной библиотеки как ```json```, ```csv``` и ```pickle```. 5 | Неотъемлемой частью работы с файлами является работа с путями. Для этого 6 | здесь используется модули ```os.path``` и ```pathlib```. 7 | 8 | - [5.1 Файлы. Чтение и запись](01_files.ipynb) 9 | - [5.2 Модуль ```io```](02_io.ipynb) 10 | - [5.3 Менеджеры контекста](03_cmanagers.ipynb) 11 | - [5.4 Модуль ```json```](04_json.ipynb) 12 | - [5.5 Модуль ```csv```](05_csv.ipynb) 13 | - [5.6 Модуль ```pickle```](06_pickle.ipynb) 14 | - [5.7 Модуль ```os.path```](07_os_path.ipynb) 15 | - [5.8 Модуль ```pathlib```](08_pathlib.ipynb) 16 | 17 | [К содержанию](../../README.md) 18 | 19 | [6. Классы](../06_classes/00_overview.md) 20 | -------------------------------------------------------------------------------- /python_pd/05_files/02_io.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Модуль ```io```\n", 27 | "\n", 28 | "Модуль ```io``` предоставляет основные возможности Python для работы с различными типами ввода-вывода. Существует три основных типа ввода-вывода: \n", 29 | "- текстовый ввод-вывод; \n", 30 | "- двоичный ввод-вывод;\n", 31 | "- необработанный ввод-вывод. \n", 32 | "\n", 33 | "Как уже описывалось в [пункте про файлы](01_files.ipynb) потоки и файловые объекты независимо от своей категории могут иметь разные свойства:\n", 34 | "\n", 35 | "- ограничения доступа (только чтение, только запись, запись и чтение);\n", 36 | "- произвольные доступ (например, допустим для файлов, и недопустим для сокетов);\n", 37 | "- формат данных (текстовый или бинарный).\n", 38 | "\n", 39 | "Потоки могут быть связаны с реальным файлом на диске или просто представлять кусок памяти. Примером текстового потока является результат выполнения функуции ```open``` в режим которых не содержит флага ```b```. Результат функции ```open``` имеет тип [```TextIOWrapper```](https://docs.python.org/3/library/io.html#io.TextIOWrapper). Это текстовый поток, который реализован поверх двоичного [```BufferedIOBase```](https://docs.python.org/3/library/io.html#io.BufferedIOBase)." 40 | ], 41 | "cell_type": "markdown", 42 | "metadata": {} 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 1, 47 | "metadata": {}, 48 | "outputs": [ 49 | { 50 | "output_type": "stream", 51 | "name": "stdout", 52 | "text": [ 53 | "f = <_io.TextIOWrapper name='python_pd\\\\05_files\\\\data.txt' mode='r' encoding='cp1251'>\n" 54 | ] 55 | } 56 | ], 57 | "source": [ 58 | "f = open(r'python_pd\\05_files\\data.txt', mode='r')\n", 59 | "print(f'{f = }')\n", 60 | "f.close()" 61 | ] 62 | }, 63 | { 64 | "source": [ 65 | "Добавление флага ```b``` приводит к появлению бинарных потоков:\n", 66 | "- ```r``` - ```BufferedReader```\n", 67 | "- ```r+```, ```w+``` или ```a+``` - ```BufferedRandom```\n", 68 | "- ```w``` или ```a``` - ```BufferedWriter```" 69 | ], 70 | "cell_type": "markdown", 71 | "metadata": {} 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": 2, 76 | "metadata": {}, 77 | "outputs": [ 78 | { 79 | "output_type": "stream", 80 | "name": "stdout", 81 | "text": [ 82 | "f = <_io.BufferedReader name='python_pd\\\\05_files\\\\data.txt'>\ndata = b''\ntype(data) = \ndata.decode(encoding=\"cp1251\") = ''\n" 83 | ] 84 | } 85 | ], 86 | "source": [ 87 | "f = open(r'python_pd\\05_files\\data.txt', mode='rb')\n", 88 | "print(f'{f = }')\n", 89 | "data = f.read()\n", 90 | "f.close()\n", 91 | "\n", 92 | "print(f'{data = }') # файл тектовый - результат строка байт\n", 93 | "print(f'{type(data) = }')\n", 94 | "print(f'{data.decode(encoding=\"cp1251\") = }') # декодирование строки байт в текст" 95 | ] 96 | }, 97 | { 98 | "source": [ 99 | "Бинарные потоки можно преобразовать в текстовые." 100 | ], 101 | "cell_type": "markdown", 102 | "metadata": {} 103 | }, 104 | { 105 | "cell_type": "code", 106 | "execution_count": 3, 107 | "metadata": {}, 108 | "outputs": [ 109 | { 110 | "output_type": "stream", 111 | "name": "stdout", 112 | "text": [ 113 | "type(f) = \ntype(new_f) = \nf.closed = True\nnew_f.closed = True\n" 114 | ] 115 | } 116 | ], 117 | "source": [ 118 | "from io import TextIOWrapper\n", 119 | "\n", 120 | "f = open(r'python_pd\\05_files\\data.txt', mode='rb')\n", 121 | "print(f'{type(f) = }')\n", 122 | "new_f = TextIOWrapper(f, encoding='cp1257')\n", 123 | "print(f'{type(new_f) = }')\n", 124 | "f.close()\n", 125 | "\n", 126 | "# закрытие исходного потока привело к закрытию текстового\n", 127 | "print(f'{f.closed = }')\n", 128 | "print(f'{new_f.closed = }')" 129 | ] 130 | }, 131 | { 132 | "source": [ 133 | "Как упоминалось выше, потоки могут быть не привязаны к реальным объектам на диске." 134 | ], 135 | "cell_type": "markdown", 136 | "metadata": {} 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": 4, 141 | "metadata": {}, 142 | "outputs": [ 143 | { 144 | "output_type": "stream", 145 | "name": "stdout", 146 | "text": [ 147 | "(1): f.tell() = 14\n(2): f.read() = 'Hello, Monty\\n'\n(3): b.tell() = 14\n(4): f.tell() = 0\n(5): b.read() = b'Hello, Monty\\r\\n'\n" 148 | ] 149 | } 150 | ], 151 | "source": [ 152 | "import io\n", 153 | "\n", 154 | "# создадим текстовый поток\n", 155 | "b = io.BytesIO(b'')\n", 156 | "f = TextIOWrapper(b, encoding='utf-8')\n", 157 | "\n", 158 | "# запишем текст в поток через print\n", 159 | "print('Hello, Monty', file=f)\n", 160 | "\n", 161 | "# указатель передвинулся в конец\n", 162 | "print(f'(1): {f.tell() = }')\n", 163 | "\n", 164 | "# для чтения из потока передвинем указатель\n", 165 | "f.seek(0)\n", 166 | "print(f'(2): {f.read() = }')\n", 167 | "\n", 168 | "# манипуляции с f сказываются на b и наоборот\n", 169 | "print(f'(3): {b.tell() = }')\n", 170 | "b.seek(0)\n", 171 | "print(f'(4): {f.tell() = }')\n", 172 | "print(f'(5): {b.read() = }')\n", 173 | "\n", 174 | "b.close()" 175 | ] 176 | }, 177 | { 178 | "source": [ 179 | "Аналогом ```BytesIO``` будет [```StringIO```](https://docs.python.org/3/library/io.html#io.StringIO) для типа ```str```." 180 | ], 181 | "cell_type": "markdown", 182 | "metadata": {} 183 | }, 184 | { 185 | "source": [ 186 | "# Полезные ссылки\n", 187 | "\n", 188 | "- [Документация](https://docs.python.org/3/library/io.html)\n", 189 | "- [What's the difference between '_io' and 'io'?](https://stackoverflow.com/questions/26208863/whats-the-difference-between-io-and-io/26208902)\n", 190 | "- [What's the difference between io.open() and os.open() on Python?](https://stackoverflow.com/questions/7219511/whats-the-difference-between-io-open-and-os-open-on-python)" 191 | ], 192 | "cell_type": "markdown", 193 | "metadata": {} 194 | } 195 | ] 196 | } -------------------------------------------------------------------------------- /python_pd/05_files/03_cmanagers.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.8.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "5be696dc-7900-45eb-ba9e-444d8f184671", 18 | "display_name": "'Python Interactive'" 19 | } 20 | }, 21 | "nbformat": 4, 22 | "nbformat_minor": 2, 23 | "cells": [ 24 | { 25 | "source": [ 26 | "# Менеджеры контекста\n", 27 | "\n", 28 | "Менеджеры контекста это удобный способ управления ресурсами, например, файлами, сокетами и т.д. Это короткое представление паттерна, использующего конструкцию ```try ... finaly ...```:\n", 29 | "\n", 30 | "```python\n", 31 | "r = acquire_resource() # получение ресурса\n", 32 | "try:\n", 33 | " do_something(r) # какие-либо операции с ресурсом\n", 34 | "finaly:\n", 35 | " # освобождение происходит в любом случае\n", 36 | " release_resource(r)\n", 37 | "```\n", 38 | "\n", 39 | "Менеджер контекста позволяет оставить за кадром освобождение ресурсов, т.е. действие ```release_resource``` будет вызвано неявно:\n", 40 | "\n", 41 | "```python\n", 42 | "with acquire_resource as r:\n", 43 | " do_something(r)\n", 44 | "```\n", 45 | "\n", 46 | "Для поддержки оператора ```with``` необходимо, чтобы объект реализовывал протокол менеджера контекста. Этот протокол заключается в реализации двух методов: ```__enter__``` и ```__exit__```. Первый метод служит для инициализации контекста, например, открывает файл. Значение, возвращаемое ```__enter__```, записывается в переменную по имени, указанному после оператора ```as```. Второй метод вызывается после выполнения тела оператора ```with``` и принимает три аргумента: тип исключения, само исключение, объект типа ```traceback```. Если в процессе выполнения тела оператора ```with``` было поднято исключение, метод ```__exit__``` может подави его, вернув ```True```. Любые объекты, реализующие эти два метода, будут являться менеджерами контекста. Подобное поведение без явного указания реализуемого интерфейса называется утиной типизацией." 47 | ], 48 | "cell_type": "markdown", 49 | "metadata": {} 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 1, 54 | "metadata": {}, 55 | "outputs": [ 56 | { 57 | "output_type": "stream", 58 | "name": "stdout", 59 | "text": [ 60 | "data = 'foo\\nbar\\nbaz\\nquz'\n" 61 | ] 62 | } 63 | ], 64 | "source": [ 65 | "path = r'python_pd\\05_files\\\\'\n", 66 | "with open(path + 'data.txt', 'r', encoding='cp1251') as f:\n", 67 | " data = f.read()\n", 68 | "print(f'{data = }')" 69 | ] 70 | }, 71 | { 72 | "source": [ 73 | "Оператор ```with``` позволяет работать одновременно с несколькими менеджерами контекста:\n", 74 | "\n", 75 | "```python\n", 76 | "with acquire_res() as r, acquire_other_res() as other:\n", 77 | " do_something(r, other)\n", 78 | "```\n", 79 | "\n", 80 | "Такая запись эквивалентна двум вложенным менеджерам контекста:\n", 81 | "\n", 82 | "```python\n", 83 | "with acquire_res() as r:\n", 84 | " with acquire_other_res() as other:\n", 85 | " do_something(r, other)\n", 86 | "```\n", 87 | "\n", 88 | "Однако не стоит злоупотреблять использованием первого варианта, особенно для большого количества менеджеров контекста. Порой читаемость кода будет лучше, если использовать вложенные блоки." 89 | ], 90 | "cell_type": "markdown", 91 | "metadata": {} 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 2, 96 | "metadata": {}, 97 | "outputs": [ 98 | { 99 | "output_type": "stream", 100 | "name": "stdout", 101 | "text": [ 102 | "data1 = 'foo\\nbar\\nbaz\\nquz'\ndata2 = 'Foo\\tbar\\n'\n" 103 | ] 104 | } 105 | ], 106 | "source": [ 107 | "with open(path + 'data.txt') as f1, open(path + 'write_data.txt') as f2:\n", 108 | " data1 = f1.read()\n", 109 | " data2 = f2.read()\n", 110 | "print(f'{data1 = }')\n", 111 | "print(f'{data2 = }')" 112 | ] 113 | }, 114 | { 115 | "source": [ 116 | "Оператор ```with``` можно использовать без явного указания имени переменной.\n", 117 | "\n", 118 | "```python\n", 119 | "with acquire_res():\n", 120 | " do_something()\n", 121 | "```\n", 122 | "\n", 123 | "Стандартная библиотека Python включает самые разные менеджеры контекста для различных ситуаций. При этом работа с ними единообразна. Например, модуль ```tempfile``` реализует классы для работы с временными файлами. Он содержит класс ```TemporaryFile```, который автоматически удаляет файлы при выходе из менеджера контекста. Также менеджеры контекста активно используются при асинхронной работе.\n", 124 | "\n", 125 | "О том как реализовать собственный менеджер контекста читайте в главе про классы.\n", 126 | "\n", 127 | "# Модуль ```contextlib```\n", 128 | "\n", 129 | "Модуль ```contextlib``` входит в стандартную библиотеку и включает в себя такие менеджеры контекста как:\n", 130 | "\n", 131 | "- ```closing``` – обобщение логики освобождения ресурсов, подходит для любых объектов реализующих метод ```close```;\n", 132 | "- ```redirect_stdout``` – перенаправляет вывод в стандартный поток);\n", 133 | "- ```suppress``` – позволяет подавить исключения указанных типов;\n", 134 | "- ```ContextDecorator``` – объединяет менеджеры контекста и декораторы;\n", 135 | "- ```ExitStack``` – позволяет управлять произвольным количеством менеджеров контекста (например, когда необходимо управлять произвольным количество ресурсов). \n", 136 | "\n", 137 | "Например, функция, логирующая пути открытых файлов:" 138 | ], 139 | "cell_type": "markdown", 140 | "metadata": {} 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 3, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "from contextlib import ExitStack\n", 149 | "\n", 150 | "def marge_log(path, *logs):\n", 151 | " \"\"\"Логирование открытых файлов.\n", 152 | " Логирует имена отурытых файлов с помощью \n", 153 | " класса contextlib.ExitStack.\n", 154 | "\n", 155 | " :param path: путь до лог-файла\n", 156 | " :type path: str\n", 157 | " :param logs: пути до файлов\n", 158 | " :type logs: tuple[str]\n", 159 | " \"\"\"\n", 160 | " with ExitStack() as st:\n", 161 | " # добавляем произвольное количество ресурсов в стек\n", 162 | " handles = [st.enter_context(open(log)) for log in logs]\n", 163 | " # не забываем про файл логов\n", 164 | " output = open(path, 'w')\n", 165 | " st.enter_context(output)\n", 166 | "\n", 167 | " # пишем в файл логов имена всех остальных файлов\n", 168 | " output.write('\\n'.join(h.name for h in handles))" 169 | ] 170 | }, 171 | { 172 | "source": [ 173 | "Или использование ```suppress``` для элегантного удаления файла (пример из документации)." 174 | ], 175 | "cell_type": "markdown", 176 | "metadata": {} 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 4, 181 | "metadata": {}, 182 | "outputs": [], 183 | "source": [ 184 | "from contextlib import suppress\n", 185 | "\n", 186 | "with suppress(FileNotFoundError):\n", 187 | " os.remove('somefile.tmp')" 188 | ] 189 | }, 190 | { 191 | "source": [ 192 | "Пример применения декоратора ```contextmanager```, который может сделать менеджером контекста даже функцию. \n", 193 | "\n", 194 | "В качестве примера приведена функция ```get_prefix_spaces```, которая умеет выводить на экран сообщения с отступом. При этом учитываются вложенные менеджеры контекста." 195 | ], 196 | "cell_type": "markdown", 197 | "metadata": {} 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": 5, 202 | "metadata": {}, 203 | "outputs": [ 204 | { 205 | "output_type": "stream", 206 | "name": "stdout", 207 | "text": [ 208 | " foo\n bar\n baz\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "from contextlib import contextmanager\n", 214 | "\n", 215 | "\n", 216 | "def get_prefix_spaces(indent=4):\n", 217 | " \"\"\"Фабрика менеджеров контекста печати с отступом.\n", 218 | " Для создания менеджера контекста из функции \n", 219 | " используется декоратор contextlib.contextmanager.\n", 220 | "\n", 221 | " В качестве \"хака\" для отслеживания уровня отступа \n", 222 | " используется объемлющая область видимости и оператор \n", 223 | " nonlocal для возможности редактирования.\n", 224 | "\n", 225 | " Функция _print - это обертка для print.\n", 226 | "\n", 227 | " :param indent: количество пробелов в одном уровне отступа.\n", 228 | " :type indent: int\n", 229 | " :return: менеджер контекста для печати с отступом.\n", 230 | " :rtype: Callable\n", 231 | " \"\"\"\n", 232 | " level = 0\n", 233 | " def _print(msg, *args, **kwargs):\n", 234 | " print(f'{\" \" * indent * level}{msg}', *args, **kwargs)\n", 235 | "\n", 236 | " @contextmanager\n", 237 | " def inner():\n", 238 | " nonlocal level\n", 239 | " try:\n", 240 | " level += 1\n", 241 | " yield _print\n", 242 | " finally:\n", 243 | " level -= 1\n", 244 | " return inner\n", 245 | "\n", 246 | "\n", 247 | "prefix_spaces = get_prefix_spaces()\n", 248 | "\n", 249 | "with prefix_spaces() as f:\n", 250 | " f('foo')\n", 251 | " with prefix_spaces() as f:\n", 252 | " f('bar')\n", 253 | " with prefix_spaces() as f:\n", 254 | " f('baz')\n" 255 | ] 256 | }, 257 | { 258 | "source": [ 259 | "Читайте документацию по ```contextlib``` для ознакомления с другими вариантами менеджеров контекста и примерами их использования.\n", 260 | "\n", 261 | "# Полезные ссылки\n", 262 | "\n", 263 | "- [Документация по ```contextlib```](https://docs.python.org/3/library/contextlib.html)" 264 | ], 265 | "cell_type": "markdown", 266 | "metadata": {} 267 | } 268 | ] 269 | } -------------------------------------------------------------------------------- /python_pd/05_files/04_json.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3", 19 | "language": "python" 20 | } 21 | }, 22 | "nbformat": 4, 23 | "nbformat_minor": 2, 24 | "cells": [ 25 | { 26 | "source": [ 27 | "# Модуль ```json```\n", 28 | "\n", 29 | "Формат данных ```json``` был основан на нотации языка JavaScript для обмена данными." 30 | ], 31 | "cell_type": "markdown", 32 | "metadata": {} 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 1, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "import json" 41 | ] 42 | }, 43 | { 44 | "source": [ 45 | "Модуль ```json``` поддерживает несколько функций для сериализации (кодирование) и десериализации (декодирование) данных. Сериализация или кодирование это преобразование Python объектов в строку. Для такой сериализации предусмотрена функция ```json.dumps```, которая принимает Python объект и возвращает строку. Аналогом этой функции выступает функция ```json.dump```. Она принимает объект и файл для записи этого объекта. Десериализация или декодирование это обратная сериализации операция. Она преобразует строку в Python объекты. Для десериализации модуль ```json``` предоставляет две функции ```json.loads``` и ```json.load``` аналогичных ```json.dumps``` и ```json.dump``` соответственно.\n", 46 | "\n", 47 | "Не все объекты Python могут быть сериализованы в ```json``` формат. Например, списки и кортежи сериализуются в виде массивов, а множества и комплексные числа не поддерживают сериализацию \"из коробки\". Некоторые объекты, такие как ```None```, сериализуются в аналогичные, приближенные к используемым в JavaScript. В таблице соотнесены Python типы и формат их сериализации.\n", 48 | "\n", 49 | "| Тип данных | Объект после сериализации |\n", 50 | "|---------------|---------------------------|\n", 51 | "| ```int``` | ```int``` |\n", 52 | "| ```float``` | ```float``` |\n", 53 | "| ```complex``` | Не поддерживается |\n", 54 | "| ```list``` | Массив |\n", 55 | "| ```tuple``` | Массив |\n", 56 | "| ```dict``` | Объект |\n", 57 | "| ```set``` | Не поддерживается |\n", 58 | "| ```True``` | ```true``` |\n", 59 | "| ```False``` | ```false``` |\n", 60 | "| ```None``` | ```null``` |" 61 | ], 62 | "cell_type": "markdown", 63 | "metadata": {} 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 2, 68 | "metadata": {}, 69 | "outputs": [ 70 | { 71 | "output_type": "stream", 72 | "name": "stdout", 73 | "text": [ 74 | "Целое число в json: 42\nЧисло с плавающей точкой в json: 42.0\nСписок в json: [1, 2, 3]\nКортеж в json: [1, 2, 3]\nСловарь в json: {\"1\": \"a\", \"2\": \"b\"}\nTrue в json: true\nFalse в json: false\nNone в json: null\n" 75 | ] 76 | } 77 | ], 78 | "source": [ 79 | "l = [1, 2, 3]\n", 80 | "t = tuple(l)\n", 81 | "d = {1: 'a', 2: 'b'}\n", 82 | "\n", 83 | "print(f'Целое число в json: {json.dumps(42)}')\n", 84 | "print(f'Число с плавающей точкой в json: {json.dumps(42.)}')\n", 85 | "print(f'Список в json: {json.dumps(l)}')\n", 86 | "print(f'Кортеж в json: {json.dumps(t)}')\n", 87 | "print(f'Словарь в json: {json.dumps(d)}')\n", 88 | "print(f'True в json: {json.dumps(True)}')\n", 89 | "print(f'False в json: {json.dumps(False)}')\n", 90 | "print(f'None в json: {json.dumps(None)}')" 91 | ] 92 | }, 93 | { 94 | "source": [ 95 | "При преобразовании некоторых объектов в ```json``` формат стоит помнить некоторые особенности. Например, ключи словарей в формате ```json``` всегда имеют строковый тип. Это приводит к тому, что любые Python объекты будут преобразованы в строку для записи в ```json```. Это повлияет и на обратный процесс - десериализацию." 96 | ], 97 | "cell_type": "markdown", 98 | "metadata": {} 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 3, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "output_type": "stream", 107 | "name": "stdout", 108 | "text": [ 109 | "Результат сериализации: {\"1\": \"a\", \"2.2\": \"b\", \"false\": [1, 2, 3], \"null\": true}\nРезультат десериализации: {'1': 'a', '2.2': 'b', 'false': [1, 2, 3], 'null': True}\n" 110 | ] 111 | } 112 | ], 113 | "source": [ 114 | "d = {1: 'a', 2.2: 'b', False: [1, 2, 3], None: True}\n", 115 | "res = json.dumps(d)\n", 116 | "print(f'Результат сериализации: {res}')\n", 117 | "print(f'Результат десериализации: {json.loads(res)}')" 118 | ] 119 | }, 120 | { 121 | "source": [ 122 | "В связи с тем, что ```list``` и ```tuple``` неразличимы в формате ```json```, то при обратном преобразовании будет всегда получаться ```list```." 123 | ], 124 | "cell_type": "markdown", 125 | "metadata": {} 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 4, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "output_type": "stream", 134 | "name": "stdout", 135 | "text": [ 136 | "Целое число из json: 1\nЧисло с плавающей точкой из json: 1.5\nСписок из json: [1, 2, 3]\nСловарь из json: {'1': 'a', '2': 'b'}\nTrue из json: True\nFalse из json: False\nNone из json: None\n" 137 | ] 138 | } 139 | ], 140 | "source": [ 141 | "print(f'Целое число из json: {json.loads(\"1\")}')\n", 142 | "print(f'Число с плавающей точкой из json: {json.loads(\"1.5\")}')\n", 143 | "print(f'Список из json: {json.loads(\"[1, 2, 3]\")}')\n", 144 | "\n", 145 | "s = '{\"1\": \"a\", \"2\": \"b\"}'\n", 146 | "print(f'Словарь из json: {json.loads(s)}')\n", 147 | "print(f'True из json: {json.loads(\"true\")}')\n", 148 | "print(f'False из json: {json.loads(\"false\")}')\n", 149 | "print(f'None из json: {json.loads(\"null\")}')" 150 | ] 151 | }, 152 | { 153 | "source": [ 154 | "Для настройки сериализации функции ```json.dumps``` и ```json.dump``` принимают ряд необязательных аргументов, например:\n", 155 | "- ```ensure_ascii``` - экранирование не ascii символов, по умолчанию True (все не ascii символы будут преобразованы в байты);\n", 156 | "- ```indent``` - отсутп, по умолчанию сериализация происходит в строку;\n", 157 | "- ```check_circular``` - проверка циклических ссылок в контейнерах;\n", 158 | "- ```separators``` - разделители в массивах и словарях.\n", 159 | "- и другие." 160 | ], 161 | "cell_type": "markdown", 162 | "metadata": {} 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": 5, 167 | "metadata": {}, 168 | "outputs": [ 169 | { 170 | "output_type": "stream", 171 | "name": "stdout", 172 | "text": [ 173 | "{\n \"place_id\": 204078161,\n \"osm_id\": 520248509,\n \"boundingbox\": [\n \"56.0035966\",\n \"56.0049951\",\n \"92.770395\",\n \"92.7736184\"\n ],\n \"lat\": \"56.00429815\",\n \"lon\": \"92.77089628097374\",\n \"type\": \"university\",\n \"importance\": 0.42099999999999993,\n \"address\": {\n \"house_number\": \"79\",\n \"road\": \"Свободный проспект\",\n \"suburb\": \"Октябрьский район\",\n \"city_district\": \"Октябрьский район\",\n \"city\": \"Красноярск\",\n \"county\": \"городской округ Красноярск\",\n \"state\": \"Красноярский край\",\n \"region\": \"Сибирский федеральный округ\",\n \"postcode\": \"660000\",\n \"country\": \"Россия\",\n \"country_code\": \"ru\"\n }\n}\n" 174 | ] 175 | } 176 | ], 177 | "source": [ 178 | "address = {\n", 179 | " 'place_id': 204078161, \n", 180 | " 'osm_id': 520248509, \n", 181 | " 'boundingbox': ['56.0035966', '56.0049951', '92.770395', '92.7736184'], \n", 182 | " 'lat': '56.00429815', \n", 183 | " 'lon': '92.77089628097374', \n", 184 | " 'type': 'university', \n", 185 | " 'importance': 0.42099999999999993, \n", 186 | " 'address': {\n", 187 | " 'house_number': '79', \n", 188 | " 'road': 'Свободный проспект', \n", 189 | " 'suburb': 'Октябрьский район', \n", 190 | " 'city_district': 'Октябрьский район', \n", 191 | " 'city': 'Красноярск', \n", 192 | " 'county': 'городской округ Красноярск', \n", 193 | " 'state': 'Красноярский край', \n", 194 | " 'region': 'Сибирский федеральный округ', \n", 195 | " 'postcode': '660000', \n", 196 | " 'country': 'Россия', \n", 197 | " 'country_code': 'ru'\n", 198 | " }\n", 199 | "}\n", 200 | "res = json.dumps(address, ensure_ascii=False, indent=4)\n", 201 | "print(f'{res}')" 202 | ] 203 | }, 204 | { 205 | "source": [ 206 | "Для записи и чтения из файла используйте функции ```json.dump``` и ```json.load``` соответственно." 207 | ], 208 | "cell_type": "markdown", 209 | "metadata": {} 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": null, 214 | "metadata": {}, 215 | "outputs": [], 216 | "source": [ 217 | "with open('data.json', 'w') as f:\n", 218 | " json.dump(address, f)" 219 | ] 220 | }, 221 | { 222 | "source": [ 223 | "Помимо всех вышеперечисленных базовых функций можно реализовать собственный сериализатор и десериализатор формата ```json```. Для этого модуль ```json``` предоставляет базовые класса ```json.JSONEncoder``` и ```json.JSONDecoder```." 224 | ], 225 | "cell_type": "markdown", 226 | "metadata": {} 227 | }, 228 | { 229 | "source": [ 230 | "# Полезные ссылки\n", 231 | "\n", 232 | "- [Официальный сайт json](https://www.json.org/json-ru.html)\n", 233 | "- [Документация к модулю ```json```](https://docs.python.org/3/library/json.html)\n", 234 | "- [Working With JSON Data in Python](https://realpython.com/python-json/)" 235 | ], 236 | "cell_type": "markdown", 237 | "metadata": {} 238 | } 239 | ] 240 | } -------------------------------------------------------------------------------- /python_pd/05_files/05_csv.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3.9.0 64-bit ('.venv')" 19 | }, 20 | "interpreter": { 21 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 22 | } 23 | }, 24 | "nbformat": 4, 25 | "nbformat_minor": 2, 26 | "cells": [ 27 | { 28 | "cell_type": "markdown", 29 | "source": [ 30 | "# Модуль ```csv```\r\n", 31 | "\r\n", 32 | "\r\n", 33 | "csv-файл - это тип обычного текстового файла, в котором используется определенная структура для упорядочивания табличных данных. Поскольку это простой текстовый файл, он может содержать только фактические текстовые данные, другими словами, символы ASCII или Unicode.\r\n", 34 | "\r\n", 35 | "Структура csv файла схожа с обычными таблицами. У таблиц есть несколько основных элементов:\r\n", 36 | "- заготовок;\r\n", 37 | "- строки;\r\n", 38 | "- столбцы (элементы строк).\r\n", 39 | "\r\n", 40 | "Формат csv содержит эти же элементы. Заготовок всегда располагается в первой строке файла. Заготовок опционален, т.е. он может отсутствовать. Каждая строка файла образует строку таблици. Элементы строки (столбцы) должны быть разделены определенным разделителем, который можно задать самостоятельно. Обычно символ-разделитель называется разделителем. В качестве разделителя могут использоваться разные символы, например, символы табуляции (```\\t```), двоеточия (```:```) и точки с запятой (```;```) и др. Для правильного анализа csv-файла необходимо заранее знать, какой разделитель используется.\r\n", 41 | "\r\n", 42 | "Вот как выглядит эта структура:\r\n", 43 | "\r\n", 44 | "```csv\r\n", 45 | "column1;column2;column3\r\n", 46 | "foo;bar;baz\r\n", 47 | "1;2;3.2\r\n", 48 | "```\r\n", 49 | "\r\n", 50 | "Здесь первая строка является заголовком. На самом деле она ничем не отличается от остальных.\r\n", 51 | "\r\n", 52 | "Формат csv удобен при работе с табличными данными. В этот формат можно легко преобразовать данные, полученные из базы данных. Очень часто в этом формате распространяются датасеты для анализа данных. Обычно каждый столбец этого формата имеет один тип данных, например, в датасете о погоде в столбце суточной температуры будут храниться числа с плавающей точкой. Необходимо выбирать символ для точки (запятая или точка), а также разделитель. Нельзя делать разделителем запятую, если она является разделителем в числе. Такой способ организации данных позволяет просто преобразовать данные в текстовый формат и наоборот. В связи с тем, что csv формат хранит текстовые данные, то работать с ними можно и напрямую, читая строки файла и совершая над ними какие-либо манипуляции.\r\n", 53 | "\r\n", 54 | "Основным недостатком csv формата является его плохая человекочитаемость, т.к. в большом файле трудно разобрать, где и какие данных находятся.\r\n", 55 | "\r\n", 56 | "Библиотка ```csv``` входит в стандартную библиотеку Python и предоставляет возможности для чтения и записи данных в csv-файл. Для начала работы достаточно импортировать этот модуль." 57 | ], 58 | "metadata": {} 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 10, 63 | "source": [ 64 | "import csv\r\n", 65 | "\r\n", 66 | "\r\n", 67 | "print(csv.__doc__)" 68 | ], 69 | "outputs": [ 70 | { 71 | "output_type": "stream", 72 | "name": "stdout", 73 | "text": [ 74 | "CSV parsing and writing.\n", 75 | "\n", 76 | "This module provides classes that assist in the reading and writing\n", 77 | "of Comma Separated Value (CSV) files, and implements the interface\n", 78 | "described by PEP 305. Although many CSV files are simple to parse,\n", 79 | "the format is not formally defined by a stable specification and\n", 80 | "is subtle enough that parsing lines of a CSV file with something\n", 81 | "like line.split(\",\") is bound to fail. The module supports three\n", 82 | "basic APIs: reading, writing, and registration of dialects.\n", 83 | "\n", 84 | "\n", 85 | "DIALECT REGISTRATION:\n", 86 | "\n", 87 | "Readers and writers support a dialect argument, which is a convenient\n", 88 | "handle on a group of settings. When the dialect argument is a string,\n", 89 | "it identifies one of the dialects previously registered with the module.\n", 90 | "If it is a class or instance, the attributes of the argument are used as\n", 91 | "the settings for the reader or writer:\n", 92 | "\n", 93 | " class excel:\n", 94 | " delimiter = ','\n", 95 | " quotechar = '\"'\n", 96 | " escapechar = None\n", 97 | " doublequote = True\n", 98 | " skipinitialspace = False\n", 99 | " lineterminator = '\\r\\n'\n", 100 | " quoting = QUOTE_MINIMAL\n", 101 | "\n", 102 | "SETTINGS:\n", 103 | "\n", 104 | " * quotechar - specifies a one-character string to use as the\n", 105 | " quoting character. It defaults to '\"'.\n", 106 | " * delimiter - specifies a one-character string to use as the\n", 107 | " field separator. It defaults to ','.\n", 108 | " * skipinitialspace - specifies how to interpret whitespace which\n", 109 | " immediately follows a delimiter. It defaults to False, which\n", 110 | " means that whitespace immediately following a delimiter is part\n", 111 | " of the following field.\n", 112 | " * lineterminator - specifies the character sequence which should\n", 113 | " terminate rows.\n", 114 | " * quoting - controls when quotes should be generated by the writer.\n", 115 | " It can take on any of the following module constants:\n", 116 | "\n", 117 | " csv.QUOTE_MINIMAL means only when required, for example, when a\n", 118 | " field contains either the quotechar or the delimiter\n", 119 | " csv.QUOTE_ALL means that quotes are always placed around fields.\n", 120 | " csv.QUOTE_NONNUMERIC means that quotes are always placed around\n", 121 | " fields which do not parse as integers or floating point\n", 122 | " numbers.\n", 123 | " csv.QUOTE_NONE means that quotes are never placed around fields.\n", 124 | " * escapechar - specifies a one-character string used to escape\n", 125 | " the delimiter when quoting is set to QUOTE_NONE.\n", 126 | " * doublequote - controls the handling of quotes inside fields. When\n", 127 | " True, two consecutive quotes are interpreted as one during read,\n", 128 | " and when writing, each quote character embedded in the data is\n", 129 | " written as two quotes\n", 130 | "\n" 131 | ] 132 | } 133 | ], 134 | "metadata": {} 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "source": [ 139 | "Чтение из csv-файла выполняется с помощью ```reader``` объекта. csv-файл открывается как текстовый файл встроенной функцией ```open```, которая возвращает файловый объект. Затем он передается конструктору ```reader``` объекта, который, в свою очередь, выполняет тяжелую работу.\r\n", 140 | "\r\n", 141 | "Чтение можно производить не только файлов, но и строк напрямую. Для этого необходимо функции ```csv.reader```, которая является конструктором ```reader``` объекта, передать список строк, которые необходимо разобрать." 142 | ], 143 | "metadata": {} 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 11, 148 | "source": [ 149 | "for item in csv.reader(['1,2,3', 'q,w,e', 'True,None,1 + 1j']):\r\n", 150 | " print(item)" 151 | ], 152 | "outputs": [ 153 | { 154 | "output_type": "stream", 155 | "name": "stdout", 156 | "text": [ 157 | "['1', '2', '3']\n", 158 | "['q', 'w', 'e']\n", 159 | "['True', 'None', '1 + 1j']\n" 160 | ] 161 | } 162 | ], 163 | "metadata": {} 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "source": [ 168 | "Каждая строка, возвращаемая ```reader``` объектом, представляет собой список элементов типа ```str```, содержащих данные, найденные путем удаления разделителей." 169 | ], 170 | "metadata": {} 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 12, 175 | "source": [ 176 | "with open('python_pd/05_files/data.csv', 'r') as f:\r\n", 177 | " reader = csv.reader(f, delimiter=';')\r\n", 178 | " for i, line in enumerate(reader):\r\n", 179 | " if i == 0:\r\n", 180 | " # чтение заголовка, в файле data.csv он есть\r\n", 181 | " print(f'{i}: {\" \".join(line)}')\r\n", 182 | " else:\r\n", 183 | " # вывод и выравнивание остальных строк\r\n", 184 | " print(f'{i}: {\" \".join([\" \" * (7-len(s)) + s for s in line])}')" 185 | ], 186 | "outputs": [ 187 | { 188 | "output_type": "stream", 189 | "name": "stdout", 190 | "text": [ 191 | "0: column1 column2 column3\n", 192 | "1: foo bar baz\n", 193 | "2: 1 2 3\n" 194 | ] 195 | } 196 | ], 197 | "metadata": {} 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "source": [ 202 | "Для записи данных в csv файл есть ```writer``` объект. Он создается\r\n", 203 | "классом ```csv.DictWriter```, который в качестве аргументов принимает\r\n", 204 | "файловый объект, заголовки полей и разделитель.\r\n", 205 | "\r\n", 206 | "Для записи заголовка в файл можно воспользоваться методом\r\n", 207 | "```writeheader```, без его вызова заголовой записан не будет. Запись\r\n", 208 | "самих данных, т.е. каждой строки, происходит через вызов метода\r\n", 209 | "```writerow```. Этот метод принимает словарь формата\r\n", 210 | "```{'имя_поля': значне, ...}```. Ключи этого словаря должны быть\r\n", 211 | "названиями полей или столбцов, количество ключей должно совпадать с\r\n", 212 | "количеством полей, обозначенным через атрибут ```fieldnames```\r\n", 213 | "```writer``` объекта.\r\n", 214 | "\r\n", 215 | "Используя цикл для записи данных будте внимательны и следите за тем,\r\n", 216 | "чтобы метод ```writeheader``` вызывался один раз. Иначе заголовок файла\r\n", 217 | "бедет записан несколько раз." 218 | ], 219 | "metadata": {} 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": 14, 224 | "source": [ 225 | "with open('python_pd/05_files/data.csv', 'w', newline='') as f:\r\n", 226 | " fields = ['column1', 'column2', 'column3']\r\n", 227 | " writer = csv.DictWriter(f, fieldnames=fields, delimiter=';')\r\n", 228 | " writer.writeheader()\r\n", 229 | " writer.writerow({'column1': 'foo', 'column2': 'bar', 'column3': 'baz'})\r\n", 230 | " writer.writerow({'column1': 1, 'column2': 2, 'column3': 3})" 231 | ], 232 | "outputs": [], 233 | "metadata": {} 234 | }, 235 | { 236 | "cell_type": "markdown", 237 | "source": [ 238 | "# Полезные ссылки\n", 239 | "\n", 240 | "- [Документация к модулю ```csv```](https://docs.python.org/3/library/csv.html)\n", 241 | "- [Reading and Writing CSV Files in Python](https://realpython.com/python-csv/)" 242 | ], 243 | "metadata": {} 244 | } 245 | ] 246 | } -------------------------------------------------------------------------------- /python_pd/05_files/06_pickle.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3", 19 | "language": "python" 20 | } 21 | }, 22 | "nbformat": 4, 23 | "nbformat_minor": 2, 24 | "cells": [ 25 | { 26 | "source": [ 27 | "# Модуль ```pickle```\n", 28 | "\n", 29 | "Модуль ```pickle``` реализует двоичные протоколы для сериализации и десериализации Python объектов. «Маринование» - это процесс, посредством которого Python объекты преобразуется в поток байтов, а «размаринование» - это обратная операция, посредством которой поток байтов (из двоичного файла или байтового объекта) преобразуется обратно в объекты.\n", 30 | "\n", 31 | "Протокол, используемый в ```pickle```, не просто записывает байты в файл или строку, он записывает дополнительную метаинформацию о типе объекта. Без этого будет невозможна десериализация этого байтового представления." 32 | ], 33 | "cell_type": "markdown", 34 | "metadata": {} 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": 1, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "import pickle" 43 | ] 44 | }, 45 | { 46 | "source": [ 47 | "Интерфейс, предоставляемый модулем ```pickle```, схож с интерфейсом модуля ```json```. Вот краткое описание:\n", 48 | "- ```dump(obj, file)``` - функция сериализации объекта ```obj``` в бинарный файл ```file```; \n", 49 | "- ```dumps(obj)``` - функция сериализации объекта ```obj``` в бинарную строку;\n", 50 | "- ```load(file)``` - функция десериализации объекта из бинарного файла ```file```;\n", 51 | "- ```loads(data)``` - функция десериализации объекта из бинарной строки ```data```." 52 | ], 53 | "cell_type": "markdown", 54 | "metadata": {} 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 2, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "# подготовим данные для сериализации\n", 63 | "d_1 = 'бнопня'\n", 64 | "d_2 = 196.\n", 65 | "d_3 = {\n", 66 | " 'foo': [1, 2, 3],\n", 67 | " 'bar': ('a', 'b', 'c'),\n", 68 | " 'baz': {True, False, None},\n", 69 | "}" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 3, 75 | "metadata": {}, 76 | "outputs": [ 77 | { 78 | "output_type": "stream", 79 | "name": "stdout", 80 | "text": [ 81 | "type(serialized_str) = \n -> b'\\x80\\x04\\x95\\x10\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x8c\\x0c\\xd0\\xb1\\xd0\\xbd\\xd0\\xbe\\xd0\\xbf\\xd0\\xbd\\xd1\\x8f\\x94.'\n -> b'\\x80\\x04\\x95\\n\\x00\\x00\\x00\\x00\\x00\\x00\\x00G@h\\x80\\x00\\x00\\x00\\x00\\x00.'\n -> b'\\x80\\x04\\x956\\x00\\x00\\x00\\x00\\x00\\x00\\x00}\\x94(\\x8c\\x03foo\\x94]\\x94(K\\x01K\\x02K\\x03e\\x8c\\x03bar\\x94\\x8c\\x01a\\x94\\x8c\\x01b\\x94\\x8c\\x01c\\x94\\x87\\x94\\x8c\\x03baz\\x94\\x8f\\x94(\\x89\\x88N\\x90u.'\n" 82 | ] 83 | } 84 | ], 85 | "source": [ 86 | "# сериализация\n", 87 | "serialized_str = pickle.dumps(d_1)\n", 88 | "serialized_float = pickle.dumps(d_2)\n", 89 | "serialized_dict = pickle.dumps(d_3)\n", 90 | "\n", 91 | "print(f'{type(serialized_str) = }')\n", 92 | "\n", 93 | "print(f'{type(d_1)} -> {serialized_str}')\n", 94 | "print(f'{type(d_2)} -> {serialized_float}')\n", 95 | "print(f'{type(d_3)} -> {serialized_dict}')" 96 | ] 97 | }, 98 | { 99 | "cell_type": "code", 100 | "execution_count": 4, 101 | "metadata": {}, 102 | "outputs": [ 103 | { 104 | "output_type": "stream", 105 | "name": "stdout", 106 | "text": [ 107 | "Десериализация строки: бнопня\nДесериализация числа: 196.0\nДесериализация словаря: {'foo': [1, 2, 3], 'bar': ('a', 'b', 'c'), 'baz': {False, True, None}}\n" 108 | ] 109 | } 110 | ], 111 | "source": [ 112 | "# десериализация\n", 113 | "\n", 114 | "print(f'Десериализация строки: {pickle.loads(serialized_str)}')\n", 115 | "print(f'Десериализация числа: {pickle.loads(serialized_float)}')\n", 116 | "print(f'Десериализация словаря: {pickle.loads(serialized_dict)}')" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": 5, 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [ 125 | "# не самый красивый способ создать функцию с двумя параметрами\n", 126 | "def constructor_with_two_args(name, k):\n", 127 | " # болванка\n", 128 | " def bar(a, b):\n", 129 | " pass\n", 130 | " # копирование всех нужных атрибутов\n", 131 | " bar.__name__ = name\n", 132 | " for attr_name, v in k.items():\n", 133 | " setattr(bar, attr_name, v)\n", 134 | " # возврат новой/старой функции\n", 135 | " return bar\n", 136 | "\n", 137 | "class MyPickler(pickle.Pickler):\n", 138 | " def reducer_override(self, obj):\n", 139 | " if getattr(obj, \"__name__\", None) == \"foo\":\n", 140 | " return constructor_with_two_args, (obj.__name__, \n", 141 | " {'__doc__': obj.__doc__, '__code__': obj.__code__})\n", 142 | " else:\n", 143 | " return NotImplemented" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": 5, 149 | "metadata": {}, 150 | "outputs": [ 151 | { 152 | "output_type": "stream", 153 | "name": "stdout", 154 | "text": [ 155 | "baz = .bar at 0x0000016EE1F035E0>\na + b = 3\n" 156 | ] 157 | } 158 | ], 159 | "source": [ 160 | "import io\n", 161 | "\n", 162 | "def foo(a, b):\n", 163 | " \"\"\"Функция-подопытный\"\"\"\n", 164 | " print(f'{a + b = }')\n", 165 | "\n", 166 | "# будем писать в байтовый поток\n", 167 | "f = io.BytesIO()\n", 168 | "# создаем собственный сериализатор/десериализатор\n", 169 | "pickler = MyPickler(f)\n", 170 | "\n", 171 | "# дампим функцию в бинарный поток\n", 172 | "pickler.dump(foo)\n", 173 | "\n", 174 | "# для чистоты эксперимента удалим функцию\n", 175 | "del foo\n", 176 | "\n", 177 | "# размаринуем функцию\n", 178 | "baz = pickle.loads(f.getvalue())\n", 179 | "\n", 180 | "print(f'{baz = }')\n", 181 | "\n", 182 | "baz(1, 2) # Алоха!" 183 | ] 184 | }, 185 | { 186 | "source": [ 187 | "# Сравнение ```pickle``` и других протоколов сериализации и десериализации\n", 188 | "\n", 189 | "Для понимания отличий маринования от прочих протоколов рассмотрим небольшое сравнение (выдержка из документации).\n", 190 | "\n", 191 | "## ```pickle``` vs ```marshal```\n", 192 | "\n", 193 | "В Python реализован еще один модуль для двоичной сериализации и десериализации ```marshal```. Это более низкоуровневый протоко по сравнению с ```pickle```. Его использование не рекомендуется, а предназначение заключается в поддержке файлов ```.pyc```.\n", 194 | "\n", 195 | "- Модуль ```pickle``` позволяет отслеживать уже сериализованные объекты. Это позволяет легко работать с объектами содержащими рекурсивные ссылки. Модуль ```marshal``` этого не умеет и при попытке сериализовать объект с циклическими ссылками есть высокая вероятность сломать интерпретатор.\n", 196 | "- Модуль ```pickle``` умеет работать с пользовательскими типами данных (классами), при условии, что его объявление находится в той же области видимости. ```marshal``` не имеет такой функциональности. \n", 197 | "- В связи с тем, что ```marshal``` предназначен сугубо для внутреннего использования, переносимость между разными версиями интерпретатора не гарантируется.\n", 198 | "\n", 199 | "## ```pickle``` vs ```json```\n", 200 | "\n", 201 | "- ```json``` - это **текстовый** формат, а ```pickle``` - это двоичный формат;\n", 202 | "- ```json``` удобочитаем, а ```pickle``` - нет; \n", 203 | "- ```json``` совместим и широко используется вне экосистемы Python, в то время как ```pickle``` специфичен для Python; \n", 204 | "- ```json``` по умолчанию может представлять только ограниченное количество **встроенных** типов Python и не может сериализовать пользовательские классы;\n", 205 | "- ```pickle``` может обрабатывать чрезвычайно большое количество типов Python (многие из них автоматически, благодаря умному использованию средств самоанализа Python; поддержка сложных типов может быть добавлена путем реализации конкретного API);\n", 206 | "- в отличие от ```pickle```, десериализация ненадежного ```json``` сама по себе не создает уязвимости выполнения произвольного кода." 207 | ], 208 | "cell_type": "markdown", 209 | "metadata": {} 210 | }, 211 | { 212 | "source": [ 213 | "Дополнительно стандартная библиотека Python содержит модуль ```shelve```, который использует ```pickle``` для реализации простейшей DBM-подобной базы данных. Структура такой базы данных представлена в Python как объект типа ```dict```." 214 | ], 215 | "cell_type": "markdown", 216 | "metadata": {} 217 | }, 218 | { 219 | "source": [ 220 | "# Полезные ссылки\n", 221 | "\n", 222 | "- [Документация по модулю ```pickle```](https://docs.python.org/3/library/pickle.html)\n", 223 | "- [Документация по модулю ```shelve```](https://docs.python.org/3/library/shelve.html#module-shelve)\n", 224 | "- [Пример динамического создания функции в Python](https://gist.github.com/dhagrow/d3414e3c6ae25dfa606238355aea2ca5)" 225 | ], 226 | "cell_type": "markdown", 227 | "metadata": {} 228 | } 229 | ] 230 | } -------------------------------------------------------------------------------- /python_pd/05_files/data.csv: -------------------------------------------------------------------------------- 1 | column1;column2;column3 2 | foo;bar;baz 3 | 1;2;3 4 | -------------------------------------------------------------------------------- /python_pd/05_files/data.txt: -------------------------------------------------------------------------------- 1 | foo 2 | bar 3 | baz 4 | quz -------------------------------------------------------------------------------- /python_pd/05_files/image/mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/05_files/image/mode.png -------------------------------------------------------------------------------- /python_pd/05_files/write_data.txt: -------------------------------------------------------------------------------- 1 | Foo bar 2 | -------------------------------------------------------------------------------- /python_pd/06_classes/00_overview.md: -------------------------------------------------------------------------------- 1 | # 6. Классы 2 | 3 | Данный раздел содержит описание возможностей классов в Python. Здесь 4 | затрагиваются основные составляющие объектно-ориентированного 5 | программирования на Python. 6 | 7 | - [6.1 Классы и экземпляры класса](01_class.ipynb) 8 | - [6.2 Атрибуты класса и экземпляра](02_attr.ipynb) 9 | - [6.3 Методы](03_methods.ipynb) 10 | - [6.4 Наследование](04_inheritance.ipynb) 11 | - [6.5 "Магические" методы](05_magic.ipynb) 12 | - [6.6 Протоколы](06_protocols.ipynb) 13 | - [6.7 Утиная типизация](07_duck_typing.ipynb) 14 | - [6.8 Дескрипторы и свойства](08_property.ipynb) 15 | - [6.9 Декораторы классов](09_decorators.ipynb) 16 | - [6.10 Абстрактные классы](10_abc.ipynb) 17 | - [6.11 Метаклассы](11_meta.ipynb) 18 | 19 | [К содержанию](../../README.md) 20 | 21 | [7. Импорт](../07_import/00_overview.md) -------------------------------------------------------------------------------- /python_pd/06_classes/01_class.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3", 19 | "language": "python" 20 | } 21 | }, 22 | "nbformat": 4, 23 | "nbformat_minor": 2, 24 | "cells": [ 25 | { 26 | "source": [ 27 | "# Классы и экземпляры класса\n", 28 | "\n", 29 | "Классы представляют собой средства объединения данных и поведения. Каждый новый класс задает новый тип данных и позволяет создавать объекты или экземпляры этого типа. Экземпляр может содержать атрибуты, необходимые для хранения данных и характеризующие состояние объекта, а также методы для изменения состояния, которые определяются классом. Класс является одним из ключевых понятий в объектно-ориентированном программировании (ООП).\n", 30 | "\n", 31 | "По сравнению с другими языками программирования, механизм классов Python характерен минимумом нового синтаксиса и семантики. Классы Python предоставляют все стандартные возможности объектно-ориентированного программирования: механизм наследования классов позволяет использовать несколько базовых классов, способствуя повторному использованию кода, производный класс может переопределять любые методы своего базового класса или классов, а метод может вызывать метод базового класса с тем же именем. Объекты могут содержать произвольные количества и виды данных. Как и в случае с модулями, классы обладают динамической природой Python: они создаются во время выполнения и могут быть изменены в дальнейшем после создания.\n", 32 | "\n", 33 | "Синтаксис определения класса довольно прост. Для этого используется ключевое слово ```class```, за которым следует имя класса. Имена классов принято писать, используя ```CamelCase``` или «верблюжью» нотацию.\n", 34 | "\n", 35 | "Определения классов, также как и определения функций должны располагаться до их использования.\n", 36 | "\n", 37 | "В Python классы это тоже объекты (всё – объекты!). При определении класса создается объект класса, который связывается с переменной (имя класса) в глобальной области видимости, имеющей тоже имя, что и имя класса.\n", 38 | "\n", 39 | "Объекты классов поддерживают несколько операций: создание экземпляров и ссылки на атрибуты." 40 | ], 41 | "cell_type": "markdown", 42 | "metadata": {} 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 1, 47 | "metadata": {}, 48 | "outputs": [ 49 | { 50 | "output_type": "stream", 51 | "name": "stdout", 52 | "text": [ 53 | "hasattr(A, \"__call__\") = True\ntype(foo) = \ntype(bar) = \ntype(baz) = \nfoo is bar is baz = False\n" 54 | ] 55 | } 56 | ], 57 | "source": [ 58 | "# простейший класс\n", 59 | "class A:\n", 60 | " pass\n", 61 | "\n", 62 | "# класс это вызываемый объект, т.е. он реализует специальный \n", 63 | "# метод __call__, который позволяет использовать круглые скобки\n", 64 | "print(f'{hasattr(A, \"__call__\") = }')\n", 65 | "\n", 66 | "# создание экземпляров класса путем вызова класса как функции\n", 67 | "foo = A()\n", 68 | "bar = A()\n", 69 | "baz = A()\n", 70 | "\n", 71 | "# каждый экземпляр имеет тип соответствующий классу\n", 72 | "print(f'{type(foo) = }')\n", 73 | "print(f'{type(bar) = }')\n", 74 | "print(f'{type(baz) = }')\n", 75 | "\n", 76 | "# все экземпляры это разные! объекты\n", 77 | "print(f'{foo is bar is baz = }')" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 2, 83 | "metadata": {}, 84 | "outputs": [ 85 | { 86 | "output_type": "stream", 87 | "name": "stdout", 88 | "text": [ 89 | "Обычные атрибуты: []\n\"Маггические\" атрибуты: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']\n" 90 | ] 91 | } 92 | ], 93 | "source": [ 94 | "attrs = []\n", 95 | "magic_attrs = []\n", 96 | "for attr in dir(A):\n", 97 | " if attr.startswith('__') and attr.endswith('__'):\n", 98 | " magic_attrs.append(attr)\n", 99 | " else:\n", 100 | " attrs.append(attr)\n", 101 | "\n", 102 | "# примитивный вариант класса ничего не содержит \n", 103 | "# кроме некоторых специальных атрибутов\n", 104 | "print(f'Обычные атрибуты: {attrs}')\n", 105 | "print(f'\"Маггические\" атрибуты: {magic_attrs}')" 106 | ] 107 | }, 108 | { 109 | "source": [ 110 | "Для проверки принадлежности экземпляра конкретному классу стоит использовать функцию ```isinstance```, а не другие способы." 111 | ], 112 | "cell_type": "markdown", 113 | "metadata": {} 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 3, 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "output_type": "stream", 122 | "name": "stdout", 123 | "text": [ 124 | "type(foo) == A = True\ntype(foo) is A = True\nisinstance(foo, A) = True\n" 125 | ] 126 | } 127 | ], 128 | "source": [ 129 | "print(f'{type(foo) == A = }') # Нет\n", 130 | "print(f'{type(foo) is A = }') # Нет\n", 131 | "print(f'{isinstance(foo, A) = }') # Да!" 132 | ] 133 | }, 134 | { 135 | "source": [ 136 | "Классы могут содержать строку документации, которая располагается сразу после объявления класса и использоваться для вывода справки с помощью функции ```help(B)```. Строка документации храниться в специальном атрибуте ```__doc__```, получить к нему доступ можно через точечную нотацию ```B.__doc__```." 137 | ], 138 | "cell_type": "markdown", 139 | "metadata": {} 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 4, 144 | "metadata": {}, 145 | "outputs": [ 146 | { 147 | "output_type": "stream", 148 | "name": "stdout", 149 | "text": [ 150 | "B.__doc__ = 'Это класс B'\nHelp on class B in module __main__:\n\nclass B(builtins.object)\n | Это класс B\n | \n | Data descriptors defined here:\n | \n | __dict__\n | dictionary for instance variables (if defined)\n | \n | __weakref__\n | list of weak references to the object (if defined)\n\n" 151 | ] 152 | } 153 | ], 154 | "source": [ 155 | "class B:\n", 156 | " \"\"\"Это класс B\"\"\"\n", 157 | " pass\n", 158 | "\n", 159 | "print(f'{B.__doc__ = }')\n", 160 | "help(B)" 161 | ] 162 | }, 163 | { 164 | "source": [ 165 | "# Полезные ссылки" 166 | ], 167 | "cell_type": "markdown", 168 | "metadata": {} 169 | } 170 | ] 171 | } -------------------------------------------------------------------------------- /python_pd/06_classes/07_duck_typing.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3.9.0 64-bit ('.venv')" 19 | }, 20 | "interpreter": { 21 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 22 | } 23 | }, 24 | "nbformat": 4, 25 | "nbformat_minor": 2, 26 | "cells": [ 27 | { 28 | "cell_type": "markdown", 29 | "source": [ 30 | "# Утиная типизация\r\n", 31 | "\r\n", 32 | "Часто, когда речь заходит о Python, всплывает фраза утиная типизация.\r\n", 33 | "Идею этой концепции можно выразить как:\r\n", 34 | "\r\n", 35 | ">Если это выглядит как утка, плавает как утка и крякает как утка, то\r\n", 36 | ">это, вероятно, и есть утка\r\n", 37 | "\r\n", 38 | "Утиная типизация – это концепция, характерная для языков\r\n", 39 | "программирования с динамической типизацией, согласно которой конкретный\r\n", 40 | "тип или класс объекта не важен, а важны лишь свойства и методы, которыми\r\n", 41 | "этот объект обладает. Другими словами, при работе с объектом его тип не\r\n", 42 | "проверяется, вместо этого проверяются свойства и методы этого объекта.\r\n", 43 | "Такой подход добавляет гибкости коду, позволяет полиморфно работать с\r\n", 44 | "объектами, которые никак не связаны друг с другом и могут быть объектами\r\n", 45 | "разных классов. Единственное условие, чтобы все эти объекты поддерживали\r\n", 46 | "необходимый набор свойств и методов.\r\n", 47 | "\r\n", 48 | "Глоссарий Python определяет утинную типизацию\r\n", 49 | "[так](https://docs.python.org/3/glossary.html#term-duck-typing).\r\n", 50 | "\r\n", 51 | "Утиная типизация очень похожа на интерфейсы в других языках\r\n", 52 | "программирования, например, в Java. Однако в Python не требуется\r\n", 53 | "отдельно объявлять интерфесы. Все классы, реализующие определенный набор\r\n", 54 | "методов по умолчанию следуют заданному интерфейсу.\r\n", 55 | "\r\n", 56 | "Яркими примерами утиной типизации в Python выступают протоколы. Например\r\n", 57 | "протокол итерируемого объекта, реализуя метод `__iter__` или\r\n", 58 | "`__getitem__` можно неявно реализовать возможность использование вашего\r\n", 59 | "объекта в цикле.\r\n", 60 | "\r\n", 61 | "Для примера реализуем свой протокол `Lootable` предназначенный для\r\n", 62 | "реализации логики выпадения наград. Мотивация здесь в том, чтобы сделать\r\n", 63 | "логику получения награды из побежденных врагов, сундуков, секретных мест\r\n", 64 | "и прочего сделать похожей у разных объектов.\r\n", 65 | "\r\n", 66 | "Реализацию мы можем выполнить двумя способами: простым и более\r\n", 67 | "правильным. Мы рассмотрим второй, он отличается от первого только\r\n", 68 | "наличием базового класса, который определяет методы протокола\r\n", 69 | "(аля Java-style). Это сильно помогает в статическом анализе кода,\r\n", 70 | "автодополнение и проверка типов работают гораздо лучше.\r\n", 71 | "\r\n", 72 | "Для начала определим протокол как класс, который наследуется от класса\r\n", 73 | "`Protocol` модуля `typing`. Этот модуль специально создан для аннотации\r\n", 74 | "типов в Python. Наш протокол `Lootable` будет содержать только один\r\n", 75 | "метод `loot`." 76 | ], 77 | "metadata": {} 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 1, 82 | "source": [ 83 | "from typing import Protocol\r\n", 84 | "\r\n", 85 | "\r\n", 86 | "class Lootable(Protocol):\r\n", 87 | " def loot(self):\r\n", 88 | " ..." 89 | ], 90 | "outputs": [], 91 | "metadata": {} 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "source": [ 96 | "Определим три класса, реализующих протокол `Lootable`. Стоит отметить,\r\n", 97 | "что определять класс `Lootable` и наследовать от него другие классы не\r\n", 98 | "обязательно." 99 | ], 100 | "metadata": {} 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 2, 105 | "source": [ 106 | "import random\r\n", 107 | "\r\n", 108 | "\r\n", 109 | "class WobblyStone(Lootable):\r\n", 110 | " def loot(self):\r\n", 111 | " return random.randint(0, 20)\r\n", 112 | "\r\n", 113 | "\r\n", 114 | "class Сhest(Lootable):\r\n", 115 | " def loot(self):\r\n", 116 | " return random.randint(0, 50)\r\n", 117 | "\r\n", 118 | "\r\n", 119 | "class CowKing(Lootable):\r\n", 120 | " def loot(self):\r\n", 121 | " return random.randint(100, 200)" 122 | ], 123 | "outputs": [], 124 | "metadata": {} 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "source": [ 129 | "Определим функцию `get_loot`, которая будет принимать объект, реализующи\r\n", 130 | "метод `loot`, тип этого лбъекта совершенно не важен." 131 | ], 132 | "metadata": {} 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": 3, 137 | "source": [ 138 | "def get_loot(obj: Lootable):\r\n", 139 | " print(f'Ваша награда составила {obj.loot()} золота')" 140 | ], 141 | "outputs": [], 142 | "metadata": {} 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 4, 147 | "source": [ 148 | "wobbly_stone = WobblyStone()\r\n", 149 | "old_chest = Сhest()\r\n", 150 | "сow_лing = CowKing()\r\n", 151 | "\r\n", 152 | "get_loot(wobbly_stone)\r\n", 153 | "get_loot(old_chest)\r\n", 154 | "get_loot(сow_лing)" 155 | ], 156 | "outputs": [ 157 | { 158 | "output_type": "stream", 159 | "name": "stdout", 160 | "text": [ 161 | "Ваша награда составила 3 золота\n", 162 | "Ваша награда составила 48 золота\n", 163 | "Ваша награда составила 191 золота\n" 164 | ] 165 | } 166 | ], 167 | "metadata": {} 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "source": [ 172 | "# Полезные ссылки\r\n", 173 | "\r\n", 174 | "- [Wiki: Duck typing](https://en.wikipedia.org/wiki/Duck_typing)\r\n", 175 | "- [duck-typing. Python glossary](https://docs.python.org/3/glossary.html#term-duck-typing)\r\n", 176 | "- [What is duck typing?](https://stackoverflow.com/questions/4205130/what-is-duck-typing?rq=1)\r\n", 177 | "- [Протоколы в Python: утиная типизация по-новому](https://habr.com/ru/post/557898/)\r\n" 178 | ], 179 | "metadata": {} 180 | } 181 | ] 182 | } -------------------------------------------------------------------------------- /python_pd/06_classes/08_property.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3.9.0 64-bit ('.venv')" 19 | }, 20 | "interpreter": { 21 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 22 | } 23 | }, 24 | "nbformat": 4, 25 | "nbformat_minor": 2, 26 | "cells": [ 27 | { 28 | "cell_type": "markdown", 29 | "source": [ 30 | "# Свойства (Property)\r\n", 31 | "\r\n", 32 | "В Python использование классов может быть очень гибким. Помимо механизма\r\n", 33 | "слотов, дескрипторов и примесей присутствует также механизм свойств или\r\n", 34 | "properties. Под капотом он реализован с использованием дескрипторов. Но\r\n", 35 | "знать как они работают совершенно не обязательно для использования\r\n", 36 | "свойств. В общем случае свойства позволяют модифицировать логику записи,\r\n", 37 | "чтения или удаления атрибутов, т.е. они упрощают работу с дескрипторами.\r\n", 38 | "Теперь вам не придется писать дополнительные классы для этого.\r\n", 39 | "\r\n", 40 | "Использование свойств позволяет обращаться к методам класса как к\r\n", 41 | "атрибутам, т.е. не указывая круглые скобки. Это работает только при\r\n", 42 | "условии, что метод имеет определенные аргументы или не имеет их вовсе.\r\n", 43 | "\r\n", 44 | "Рассматрим пример использования свойства с простым классов человека, у\r\n", 45 | "которого есть атрибут дата дня рождения `birthday`. Вполне логично, что\r\n", 46 | "мы не хотим хранить возраст человека в виде числа в обычном атрибуте,\r\n", 47 | "т.к. он будет периодически изменяться. Следить за этими изменениями не\r\n", 48 | "очень хочеться. С другой стороны возраст легко вычислить. Для этого\r\n", 49 | "создадим метод `age`. Зачастую возраст считает характеристикой человека,\r\n", 50 | "поэтому хотелось бы иметь атрибут `age` и не писать круглые скобки.\r\n", 51 | "Также желательно запретить его редактирование вручную. Реализуем все это\r\n", 52 | "с помощью свойств.\r\n", 53 | "\r\n", 54 | "Использование свойства, отвечающего за чтение данных очень просто,\r\n", 55 | "достаточно декорировать нужный метода декоратором `property`. Стоит\r\n", 56 | "отметить, что методы, декорируемые таком образом, не должны принимать\r\n", 57 | "никаких страбутов." 58 | ], 59 | "metadata": {} 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 1, 64 | "source": [ 65 | "from datetime import date\r\n", 66 | "\r\n", 67 | "\r\n", 68 | "class Human:\r\n", 69 | " def __init__(self, birthday):\r\n", 70 | " self.birthday = birthday\r\n", 71 | " \r\n", 72 | " @property\r\n", 73 | " def age(self):\r\n", 74 | " return (date.today() - self.birthday).days // 365" 75 | ], 76 | "outputs": [], 77 | "metadata": {} 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "source": [ 82 | "Теперь у объекта класса `Human` есть \"псевдо\" атрибут `age`. Обратиться\r\n", 83 | "к нему можно без скобок." 84 | ], 85 | "metadata": {} 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 2, 90 | "source": [ 91 | "man = Human(date(2000, 1, 1))\r\n", 92 | "print(f'{man.birthday = }')\r\n", 93 | "print(f'{man.age = }')" 94 | ], 95 | "outputs": [ 96 | { 97 | "output_type": "stream", 98 | "name": "stdout", 99 | "text": [ 100 | "man.birthday = datetime.date(2000, 1, 1)\n", 101 | "man.age = 21\n" 102 | ] 103 | } 104 | ], 105 | "metadata": {} 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "source": [ 110 | "Так как выше мы использовали только декоратор `property`, то свойство\r\n", 111 | "`age` доступно только для чтения. Попытка записи возбудит исключение\r\n", 112 | "`AttributeError`." 113 | ], 114 | "metadata": {} 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": 3, 119 | "source": [ 120 | "man.age = 42" 121 | ], 122 | "outputs": [ 123 | { 124 | "output_type": "error", 125 | "ename": "AttributeError", 126 | "evalue": "can't set attribute", 127 | "traceback": [ 128 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 129 | "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", 130 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mman\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m42\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 131 | "\u001b[1;31mAttributeError\u001b[0m: can't set attribute" 132 | ] 133 | } 134 | ], 135 | "metadata": {} 136 | }, 137 | { 138 | "cell_type": "markdown", 139 | "source": [ 140 | "Для поддержки операций записи и удаления нужно использовать декораторы в\r\n", 141 | "виде `attr_name.setter` и `attr_name.deleter` соответственно, где \r\n", 142 | "`attr_name` имя декорируемого атрибута. Стоит отметить, что для\r\n", 143 | "использования \"сеттера\" и \"делитера\" необходимо определить \"геттер\",\r\n", 144 | "т.е. свойство с декоратором `property`.\r\n", 145 | "\r\n", 146 | "Обратите внимание на сигнатуры каждого метода. Они должны бить именно\r\n", 147 | "такими. Только свойство записи модет принимать один аргумент - значение,\r\n", 148 | "которое должно быть записано." 149 | ], 150 | "metadata": {} 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 4, 155 | "source": [ 156 | "class Useless:\r\n", 157 | " def __init__(self, foo):\r\n", 158 | " self._foo = foo\r\n", 159 | "\r\n", 160 | " @property\r\n", 161 | " def foo(self):\r\n", 162 | " return self._foo\r\n", 163 | "\r\n", 164 | " @foo.setter\r\n", 165 | " def foo(self, value):\r\n", 166 | " print('Попытка записи в атрибут foo')\r\n", 167 | " self._foo = value\r\n", 168 | "\r\n", 169 | " @foo.deleter\r\n", 170 | " def foo(self):\r\n", 171 | " print(f'Попытка удаления атрибута foo')\r\n", 172 | " del self._foo" 173 | ], 174 | "outputs": [], 175 | "metadata": {} 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": 5, 180 | "source": [ 181 | "useless = Useless('spam')\r\n", 182 | "print(f'{useless.foo = }')" 183 | ], 184 | "outputs": [ 185 | { 186 | "output_type": "stream", 187 | "name": "stdout", 188 | "text": [ 189 | "useless.foo = 'spam'\n" 190 | ] 191 | } 192 | ], 193 | "metadata": {} 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": 6, 198 | "source": [ 199 | "useless.foo = 'lovely spam'\r\n", 200 | "print(f'{useless.foo = }')" 201 | ], 202 | "outputs": [ 203 | { 204 | "output_type": "stream", 205 | "name": "stdout", 206 | "text": [ 207 | "Попытка записи в атрибут foo\n", 208 | "useless.foo = 'lovely spam'\n" 209 | ] 210 | } 211 | ], 212 | "metadata": {} 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 7, 217 | "source": [ 218 | "del useless.foo\r\n", 219 | "print(f'{useless.foo = }')" 220 | ], 221 | "outputs": [ 222 | { 223 | "output_type": "stream", 224 | "name": "stdout", 225 | "text": [ 226 | "Попытка удаления атрибута foo\n" 227 | ] 228 | }, 229 | { 230 | "output_type": "error", 231 | "ename": "AttributeError", 232 | "evalue": "'Useless' object has no attribute '_foo'", 233 | "traceback": [ 234 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 235 | "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", 236 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0museless\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfoo\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mf'{useless.foo = }'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", 237 | "\u001b[1;32m\u001b[0m in \u001b[0;36mfoo\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mfoo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_foo\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 8\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m@\u001b[0m\u001b[0mfoo\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msetter\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 238 | "\u001b[1;31mAttributeError\u001b[0m: 'Useless' object has no attribute '_foo'" 239 | ] 240 | } 241 | ], 242 | "metadata": {} 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "source": [ 247 | "Использование свойств особенно интересно в тех ситуациях, когда значение\r\n", 248 | "атрибута не нужно хранить и оно может быть вычислено (см. пример с\r\n", 249 | "`age`). Существует вариант кешированного свойства, вычисляемого один\r\n", 250 | "раз. Свойства также можно применять для ограничения доступа (см. пример\r\n", 251 | "c `foo`), когда к ограниченному атрибуту предоставляется доступ через\r\n", 252 | "свойства. Конечно, это не гарантирует полного сокрытия. " 253 | ], 254 | "metadata": {} 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "source": [ 259 | "# Полезные ссылки\r\n", 260 | "\r\n", 261 | "- [Properties](https://docs.python.org/3/howto/descriptor.html#properties)\r\n", 262 | "- [How does the `@property` decorator work in Python?](https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work-in-python)\r\n" 263 | ], 264 | "metadata": {} 265 | } 266 | ] 267 | } -------------------------------------------------------------------------------- /python_pd/06_classes/09_decorators.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": 3 14 | }, 15 | "orig_nbformat": 2 16 | }, 17 | "nbformat": 4, 18 | "nbformat_minor": 2, 19 | "cells": [ 20 | { 21 | "cell_type": "markdown", 22 | "source": [ 23 | "# Декораторы классов" 24 | ], 25 | "metadata": {} 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "source": [], 31 | "outputs": [], 32 | "metadata": {} 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "source": [ 37 | "# Полезные ссылки\r\n", 38 | "\r\n", 39 | "- [Python decorators in classes](https://stackoverflow.com/questions/1263451/python-decorators-in-classes)\r\n", 40 | "- [Сила и красота декораторов](https://habr.com/ru/post/46306/)\r\n", 41 | "- [Python Decorators](https://wiki.python.org/moin/PythonDecorators)\r\n", 42 | "- [Using Class Decorators in Python](https://towardsdatascience.com/using-class-decorators-in-python-2807ef52d273)\r\n", 43 | "- [Понимаем декораторы в Python'e, шаг за шагом. Шаг 2](https://habr.com/ru/post/141501/)\r\n" 44 | ], 45 | "metadata": {} 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /python_pd/06_classes/10_abc.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": 3 14 | }, 15 | "orig_nbformat": 2 16 | }, 17 | "nbformat": 4, 18 | "nbformat_minor": 2, 19 | "cells": [ 20 | { 21 | "cell_type": "markdown", 22 | "source": [ 23 | "# Абстрактные классы и модуль ```abc```" 24 | ], 25 | "metadata": {} 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "source": [], 31 | "outputs": [], 32 | "metadata": {} 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "source": [ 37 | "# Полезные ссылки\r\n", 38 | "\r\n", 39 | "- [abc — Abstract Base Classes](https://docs.python.org/3/library/abc.html)\r\n", 40 | "- [Why use Abstract Base Classes in Python?](https://stackoverflow.com/questions/3570796/why-use-abstract-base-classes-in-python)\r\n" 41 | ], 42 | "metadata": {} 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /python_pd/06_classes/11_meta.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "language_info": { 4 | "codemirror_mode": { 5 | "name": "ipython", 6 | "version": 3 7 | }, 8 | "file_extension": ".py", 9 | "mimetype": "text/x-python", 10 | "name": "python", 11 | "nbconvert_exporter": "python", 12 | "pygments_lexer": "ipython3", 13 | "version": "3.9.0-final" 14 | }, 15 | "orig_nbformat": 2, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3", 19 | "language": "python" 20 | } 21 | }, 22 | "nbformat": 4, 23 | "nbformat_minor": 2, 24 | "cells": [ 25 | { 26 | "source": [ 27 | "# Метаклассы" 28 | ], 29 | "cell_type": "markdown", 30 | "metadata": {} 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": 4, 42 | "metadata": {}, 43 | "outputs": [ 44 | { 45 | "output_type": "stream", 46 | "name": "stdout", 47 | "text": [ 48 | "a.foo = 5\nb.foo = 5\na is b = True\n" 49 | ] 50 | } 51 | ], 52 | "source": [ 53 | "class MetaSingleton(type):\n", 54 | " def __init__(self, *args, **kwargs):\n", 55 | " super().__init__(*args, **kwargs)\n", 56 | " self.__instance = None\n", 57 | " \n", 58 | " def __call__(self, *args, **kwargs):\n", 59 | " if self.__instance is None:\n", 60 | " self.__instance = super().__call__(*args, **kwargs)\n", 61 | " return self.__instance\n", 62 | "\n", 63 | "class A(metaclass=MetaSingleton):\n", 64 | " def __init__(self, a):\n", 65 | " self.foo = a\n", 66 | "\n", 67 | "a = A(5)\n", 68 | "b = A(0)\n", 69 | "\n", 70 | "print(f'{a.foo = }')\n", 71 | "print(f'{b.foo = }')\n", 72 | "print(f'{a is b = }')" 73 | ] 74 | }, 75 | { 76 | "source": [ 77 | "# Полезные ссылки\n", 78 | "\n", 79 | "- [Что такое метаклассы в Python?](https://ru.stackoverflow.com/questions/1208241/%d0%a7%d1%82%d0%be-%d1%82%d0%b0%d0%ba%d0%be%d0%b5-%d0%bc%d0%b5%d1%82%d0%b0%d0%ba%d0%bb%d0%b0%d1%81%d1%81%d1%8b-%d0%b2-python)\n", 80 | "- [What are metaclasses in Python?](https://stackoverflow.com/questions/100003/what-are-metaclasses-in-python/100146)\n", 81 | "- [Why is __init__() always called after __new__()?](https://stackoverflow.com/questions/674304/why-is-init-always-called-after-new)" 82 | ], 83 | "cell_type": "markdown", 84 | "metadata": {} 85 | } 86 | ] 87 | } -------------------------------------------------------------------------------- /python_pd/06_classes/image/attr_cls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/06_classes/image/attr_cls.png -------------------------------------------------------------------------------- /python_pd/06_classes/image/attr_self.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/06_classes/image/attr_self.png -------------------------------------------------------------------------------- /python_pd/06_classes/image/diamond_inh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/06_classes/image/diamond_inh.png -------------------------------------------------------------------------------- /python_pd/06_classes/image/diamond_inh_object.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/06_classes/image/diamond_inh_object.png -------------------------------------------------------------------------------- /python_pd/06_classes/image/inh_graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/06_classes/image/inh_graph.png -------------------------------------------------------------------------------- /python_pd/06_classes/image/inh_graph_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/06_classes/image/inh_graph_2.png -------------------------------------------------------------------------------- /python_pd/06_classes/image/inh_graph_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/redb0/python-bp/d03a0833bdf3737f7227b51df6e0242a79264029/python_pd/06_classes/image/inh_graph_3.png -------------------------------------------------------------------------------- /python_pd/07_import/00_overview.md: -------------------------------------------------------------------------------- 1 | # 7. Импорт 2 | 3 | Здесь дано описание работы модулей в Python, а также системы импорта. 4 | Приводится варианты импорта и рассматриваются их достоинства и 5 | недостатки, варианты применения. 6 | 7 | - [7.1 Модули и пакеты](01_modules.ipynb) 8 | - [7.2 Абсолютный и относительный импорт](02_types_imports.ipynb) 9 | - [7.3 Система импорта](03_system.ipynb) 10 | - [7.4 Поиск модулей и пакетов](04_search.ipynb) 11 | - [7.5 `pip`](05_pip.ipynb) 12 | - [7.6 Виртуальное окружение](06_venv.ipynb) 13 | - [7.7 PyPI](07_pypi.ipynb) 14 | 15 | [К содержанию](../../README.md) 16 | -------------------------------------------------------------------------------- /python_pd/07_import/01_modules.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# Модули\r\n", 7 | "\r\n", 8 | "Любой проект на языке Python, как и сам язык состоит из модулей и\r\n", 9 | "пакетов. По мере роста программы появляется необходимость в\r\n", 10 | "структурировании кода. Вы можете разделить ее на несколько файлов для\r\n", 11 | "облегчения поддержки и модификаций. Вы также можете легко\r\n", 12 | "переиспользовать функции, которую вы написали в других программах, не\r\n", 13 | "копируя ее определение в каждый файл.\r\n", 14 | "\r\n", 15 | "Согласно [документации](https://docs.python.org/3/tutorial/modules.html),\r\n", 16 | "модули это файлы с кодом, куда помещаются определения классов, функций\r\n", 17 | "и переменных, а также операторы Python. Имя файла состоит из имени\r\n", 18 | "модуля и расширения `.py`. Внутри модуля, его имя в виде строки \r\n", 19 | "храниться в глобальной дандер-переменной с именем `__name__`.\r\n", 20 | "\r\n", 21 | "На имена модулей накладываются те же ограничения, что и на любой\r\n", 22 | "идентификатор. Т. е. имя модуля не должно начинаться с цифры и содержать\r\n", 23 | "пробелов, может содержать строчные и заглавные буквы, нижние\r\n", 24 | "подчеркивания и цифры (начиная со второго символа). Например, имя\r\n", 25 | "`foo_bar.py` будет корректным именем модуля, а `foo bar.py` нет. Стоит\r\n", 26 | "упомянуть, что именовать модули по стандарту нужно в стиле `snake_case`." 27 | ], 28 | "metadata": {} 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "source": [ 33 | "# Пакеты" 34 | ], 35 | "metadata": {} 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "source": [ 40 | "# Полезные ссылки\r\n", 41 | "\r\n", 42 | "- [Documentation on modules](https://docs.python.org/3/tutorial/modules.html)" 43 | ], 44 | "metadata": {} 45 | } 46 | ], 47 | "metadata": { 48 | "orig_nbformat": 4, 49 | "language_info": { 50 | "name": "python", 51 | "version": "3.9.0" 52 | }, 53 | "kernelspec": { 54 | "name": "python3", 55 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)" 56 | }, 57 | "interpreter": { 58 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 59 | } 60 | }, 61 | "nbformat": 4, 62 | "nbformat_minor": 2 63 | } -------------------------------------------------------------------------------- /python_pd/07_import/02_types_imports.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# Импорт" 7 | ], 8 | "metadata": {} 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "source": [ 13 | "# Абсолютный и относительный импорт" 14 | ], 15 | "metadata": {} 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "# Циклически импорт" 21 | ], 22 | "metadata": {} 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "source": [ 27 | "# Полезные ссылки\r\n" 28 | ], 29 | "metadata": {} 30 | } 31 | ], 32 | "metadata": { 33 | "orig_nbformat": 4, 34 | "language_info": { 35 | "name": "python", 36 | "version": "3.9.0" 37 | }, 38 | "kernelspec": { 39 | "name": "python3", 40 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)" 41 | }, 42 | "interpreter": { 43 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 44 | } 45 | }, 46 | "nbformat": 4, 47 | "nbformat_minor": 2 48 | } -------------------------------------------------------------------------------- /python_pd/07_import/03_system.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# Система импорта" 7 | ], 8 | "metadata": {} 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "source": [ 13 | "# Полезные ссылки\r\n" 14 | ], 15 | "metadata": {} 16 | } 17 | ], 18 | "metadata": { 19 | "orig_nbformat": 4, 20 | "language_info": { 21 | "name": "python", 22 | "version": "3.9.0", 23 | "mimetype": "text/x-python", 24 | "codemirror_mode": { 25 | "name": "ipython", 26 | "version": 3 27 | }, 28 | "pygments_lexer": "ipython3", 29 | "nbconvert_exporter": "python", 30 | "file_extension": ".py" 31 | }, 32 | "kernelspec": { 33 | "name": "python3", 34 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)" 35 | }, 36 | "interpreter": { 37 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 38 | } 39 | }, 40 | "nbformat": 4, 41 | "nbformat_minor": 2 42 | } -------------------------------------------------------------------------------- /python_pd/07_import/04_search.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# Поиск модулей и пакетов" 7 | ], 8 | "metadata": {} 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "source": [ 13 | "# Реализация своего варианта поиска" 14 | ], 15 | "metadata": {} 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "source": [ 20 | "# Реализация своего варианта загрузки модуля\r\n" 21 | ], 22 | "metadata": {} 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "source": [ 27 | "# Полезные ссылки\r\n" 28 | ], 29 | "metadata": {} 30 | } 31 | ], 32 | "metadata": { 33 | "orig_nbformat": 4, 34 | "language_info": { 35 | "name": "python", 36 | "version": "3.9.0", 37 | "mimetype": "text/x-python", 38 | "codemirror_mode": { 39 | "name": "ipython", 40 | "version": 3 41 | }, 42 | "pygments_lexer": "ipython3", 43 | "nbconvert_exporter": "python", 44 | "file_extension": ".py" 45 | }, 46 | "kernelspec": { 47 | "name": "python3", 48 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)" 49 | }, 50 | "interpreter": { 51 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 52 | } 53 | }, 54 | "nbformat": 4, 55 | "nbformat_minor": 2 56 | } -------------------------------------------------------------------------------- /python_pd/07_import/05_pip.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# `pip`\r\n", 7 | "\r\n", 8 | "`pip` это система управления пакетами, которая используется для\r\n", 9 | "установки и управлениями программными пакетами, написанными на Python. \r\n", 10 | "Версия дистрибутива Python 3.4+ уже содержит пакет `pip` по умолчанию.\r\n", 11 | "\r\n", 12 | "Запросить справку по всем командам можно используя команду `help`:\r\n", 13 | "\r\n", 14 | "```bash\r\n", 15 | "> python -m pip help\r\n", 16 | "```\r\n", 17 | "\r\n", 18 | "Для просмотра установленных пакетов и их версий можно \r\n", 19 | "использовать команду `list`:\r\n", 20 | "\r\n", 21 | "```bash\r\n", 22 | "> python -m pip list\r\n", 23 | "```\r\n", 24 | "\r\n", 25 | "Используя команду `show` можно просмотреть информацию об установленном\r\n", 26 | "пакете:\r\n", 27 | "\r\n", 28 | "```bash\r\n", 29 | "> python -m pip show numpy\r\n", 30 | "```\r\n", 31 | "\r\n", 32 | "Поиск пакетов по PyPI осуществляет команда `search`. Она также\r\n", 33 | "показывает, какой пакет (его текущую версию и последнюю доступную) из\r\n", 34 | "результатов поиска был установлен.\r\n", 35 | "\r\n", 36 | "```bash\r\n", 37 | "> python -m pip search numpy\r\n", 38 | "```\r\n", 39 | "\r\n", 40 | "Для установки пакета используется команда `install` и `uninstall` для\r\n", 41 | "удаления. Также существует возможность обновить пакет с помощью опции\r\n", 42 | "`--upgrade` или короткого варианта `–U` (`pip install numpy --upgrade`).\r\n", 43 | "При установке можно указать либо определенную версию, либо минимальную\r\n", 44 | "версию, используя `==` и `>=` соответственно.\r\n", 45 | "\r\n", 46 | "```bash\r\n", 47 | "> pip install numpy>=1.16\r\n", 48 | "```\r\n", 49 | "\r\n", 50 | "Используя команду `install`, установка пакета будет произведена в\r\n", 51 | "глобальное окружение в директорию `Lib\\site-packages`. Для\r\n", 52 | "предотвращения этого нужно использовать опцию `--user`, тогда пакет\r\n", 53 | "будет установлен в `Lib\\site-packages` текущего пользователя.\r\n", 54 | "\r\n", 55 | "Существует возможность узнать, для каких из установленных пакетов \r\n", 56 | "вышли новые версии:\r\n", 57 | "\r\n", 58 | "```bash\r\n", 59 | "> pip list -o\r\n", 60 | "```\r\n", 61 | "\r\n", 62 | "Подробнее ознакомиться о `pip` можно в\r\n", 63 | "[официальной документации](https://pip.pypa.io/en/stable/).\r\n", 64 | "\r\n", 65 | "# `requirements.txt`\r\n", 66 | "\r\n", 67 | "В больших проектах с десятками зависимостей держать в голове весь список\r\n", 68 | "и их версий бывает трудно. Также при развертывании таких проектов совсем\r\n", 69 | "не хочется писать множество команд `pip install ...`. Для автоматизации\r\n", 70 | "процесса установки множества зависимостей, а также для удобного контроля\r\n", 71 | "их версий `pip` предоставляет возможность установки пакетов, указанных в\r\n", 72 | "специальном файле `requirements.txt`. Ниже приведен пример содержимого\r\n", 73 | "такого файла.\r\n", 74 | "\r\n", 75 | "```\r\n", 76 | "Django>=3.1.2\r\n", 77 | "geopy>=2.0.0\r\n", 78 | "numpy==1.20.2\r\n", 79 | "plotly\r\n", 80 | "pandas\r\n", 81 | "scipy\r\n", 82 | "```\r\n", 83 | "\r\n", 84 | "Создать файл `requirements.txt` можно с помощью команды `freeze`:\r\n", 85 | "\r\n", 86 | "```bash\r\n", 87 | "> pip freeze > requirements.txt\r\n", 88 | "```\r\n", 89 | "\r\n", 90 | "Автоматическая установка всех пакетов из этого файла осуществляется\r\n", 91 | "одной командой:\r\n", 92 | "\r\n", 93 | "```bash\r\n", 94 | "> pip install -r requirements.txt\r\n", 95 | "```" 96 | ], 97 | "metadata": {} 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "source": [ 102 | "# Аналоги менеджера пакетов `pip`\r\n", 103 | "\r\n", 104 | "## `pipenv`\r\n", 105 | "\r\n", 106 | "[Инструмент `pipenv`](https://pipenv.pypa.io/en/latest/), объединяет\r\n", 107 | "`pip` и `virtualenv`. Позволяет не только устанавливать пакеты, но и\r\n", 108 | "управлять виртуальными окружениями. В отличии от `pip` автоматически\r\n", 109 | "ведет учет зависимостей в файлах `Pipfile` и `Pipfile.lock`, учитывая\r\n", 110 | "граф зависимостей, который можно просмотреть командой `graph`.\r\n", 111 | "\r\n", 112 | "Установка пакета осуществляется просто:\r\n", 113 | "\r\n", 114 | "```bash\r\n", 115 | "> pipenv install requests\r\n", 116 | "```\r\n", 117 | "\r\n", 118 | "`pipenv` умеет отдельно вести список dev-зависимостей. Это очень\r\n", 119 | "полезный функционал, который позволяет уменьшить размер окружения. По\r\n", 120 | "умолчанию `pipenv` устанавливает пакет как основную зависимость. Что бы\r\n", 121 | "указать, что зависимость нужна только для разработки нужно добавить\r\n", 122 | "флаг `--dev`:\r\n", 123 | "\r\n", 124 | "```bash\r\n", 125 | "> pipenv install --dev flake8\r\n", 126 | "```\r\n", 127 | "\r\n", 128 | "Поддерживается возможность установки пакетов из `requirements.txt` с\r\n", 129 | "автоматическим обновлением файлов зависимостей. Также можно легко\r\n", 130 | "экспортировать как основные зависимостей, так и dev:\r\n", 131 | "\r\n", 132 | "```bash\r\n", 133 | "> pipenv lock -r > requirements.txt\r\n", 134 | "> pipenv lock -r --dev-only > dev-requirements.txt\r\n", 135 | "```\r\n", 136 | "\r\n", 137 | "Обладает дополнительным функционалом автоматизации сборки и публикации\r\n", 138 | "проекта.\r\n", 139 | "\r\n", 140 | "Подробнее о проекте читайте в\r\n", 141 | "[документации](https://pipenv.pypa.io/en/latest/).\r\n", 142 | "\r\n", 143 | "## `Poetry`\r\n", 144 | "\r\n", 145 | "`Poetry` это еще один из инструментов, позволяющих автоматизировать\r\n", 146 | "управление зависимостями проекта. Возможности этого инструмента\r\n", 147 | "довольно обширны:\r\n", 148 | "- создание виртуального окружения\r\n", 149 | "- установка пакетов\r\n", 150 | "- отслеживание зависимостей устанавливаемых пакетов\r\n", 151 | "- автоматизация сборки и публикации\r\n", 152 | "- разделение зависимостей на основные и dev \r\n", 153 | "- и др.\r\n", 154 | "\r\n", 155 | "Установить `Poetry` довольно просто:\r\n", 156 | "\r\n", 157 | "```bash\r\n", 158 | "> pip install poetry\r\n", 159 | "```\r\n", 160 | "\r\n", 161 | "Добавление пакета к текущему окружению осуществляется командой `add`:\r\n", 162 | "\r\n", 163 | "```bash\r\n", 164 | "> poetry add requests\r\n", 165 | "```\r\n", 166 | "\r\n", 167 | "Мы рассмотрим этот инструмент подробнее в следующем параграфе о\r\n", 168 | "виртуальных окружениях." 169 | ], 170 | "metadata": {} 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "source": [ 175 | "# Полезные ссылки\r\n", 176 | "\r\n", 177 | "- [pip (package manager)](https://en.wikipedia.org/wiki/Pip_(package_manager))\r\n", 178 | "- [Зачем использовать `python -m pip`](https://habr.com/ru/company/otus/blog/475392/)\r\n", 179 | "- [`pip` documentation](https://pip.pypa.io/en/stable/)\r\n", 180 | "- [Installing Python Modules](https://docs.python.org/3/installing/index.html)\r\n", 181 | "- [`pipenv`](https://pipenv.pypa.io/en/latest/)\r\n", 182 | "- [`poetry`](https://python-poetry.org/)\r\n", 183 | "- [What is the difference between venv, pyvenv, pyenv, virtualenv, virtualenvwrapper, pipenv, etc?](https://stackoverflow.com/questions/41573587/what-is-the-difference-between-venv-pyvenv-pyenv-virtualenv-virtualenvwrappe)" 184 | ], 185 | "metadata": {} 186 | } 187 | ], 188 | "metadata": { 189 | "orig_nbformat": 4, 190 | "language_info": { 191 | "name": "python", 192 | "version": "3.9.0", 193 | "mimetype": "text/x-python", 194 | "codemirror_mode": { 195 | "name": "ipython", 196 | "version": 3 197 | }, 198 | "pygments_lexer": "ipython3", 199 | "nbconvert_exporter": "python", 200 | "file_extension": ".py" 201 | }, 202 | "kernelspec": { 203 | "name": "python3", 204 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)" 205 | }, 206 | "interpreter": { 207 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 208 | } 209 | }, 210 | "nbformat": 4, 211 | "nbformat_minor": 2 212 | } -------------------------------------------------------------------------------- /python_pd/07_import/06_venv.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# Виртуальное окружение" 7 | ], 8 | "metadata": {} 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "source": [ 13 | "# Полезные ссылки\r\n" 14 | ], 15 | "metadata": {} 16 | } 17 | ], 18 | "metadata": { 19 | "orig_nbformat": 4, 20 | "language_info": { 21 | "name": "python", 22 | "version": "3.9.0" 23 | }, 24 | "kernelspec": { 25 | "name": "python3", 26 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)" 27 | }, 28 | "interpreter": { 29 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 30 | } 31 | }, 32 | "nbformat": 4, 33 | "nbformat_minor": 2 34 | } -------------------------------------------------------------------------------- /python_pd/07_import/07_pypi.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "source": [ 6 | "# PyPI" 7 | ], 8 | "metadata": {} 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "source": [ 13 | "# Полезные ссылки\r\n" 14 | ], 15 | "metadata": {} 16 | } 17 | ], 18 | "metadata": { 19 | "orig_nbformat": 4, 20 | "language_info": { 21 | "name": "python", 22 | "version": "3.9.0" 23 | }, 24 | "kernelspec": { 25 | "name": "python3", 26 | "display_name": "Python 3.9.0 64-bit ('.venv': venv)" 27 | }, 28 | "interpreter": { 29 | "hash": "178cad48488a45b94c2e1acb3bfd8ec03d0e926b0801a270a439a0363b59c19a" 30 | } 31 | }, 32 | "nbformat": 4, 33 | "nbformat_minor": 2 34 | } -------------------------------------------------------------------------------- /python_pd/best_hello_world.py: -------------------------------------------------------------------------------- 1 | """Бессмысленный и беспощадный способ реализации hello world""" 2 | 3 | import random 4 | 5 | 6 | def str_printer_decorator(number_of_str): 7 | """Декоратор печати последовательности элементов 8 | 9 | :param number_of_str: количество элементов 10 | :type number_of_str: int 11 | """ 12 | def decorator(func): 13 | def str_printer(*args): 14 | count = 0 15 | sentinel = object() 16 | def get_next_str(): 17 | nonlocal count 18 | count += 1 19 | if count <= number_of_str: 20 | return func(*args) 21 | return sentinel 22 | 23 | print(' '.join(iter(get_next_str, sentinel))) 24 | return str_printer 25 | return decorator 26 | 27 | 28 | class StringPrinterMeta(type): 29 | """Конструктор "печатающих" классов""" 30 | def __new__(cls, *args, **kwargs): 31 | model = type.__new__(cls, *args, **kwargs) 32 | @str_printer_decorator(model.number) 33 | def print_strings(): 34 | with open(__file__) as file: 35 | lines = file.readlines() 36 | i = 0 37 | while True: 38 | print(f'{i = }') 39 | line = random.choice(lines).strip() 40 | try: 41 | exec(f'{line}', {}, globals()) 42 | return string 43 | except: 44 | pass 45 | i += 1 46 | print_strings() 47 | 48 | 49 | class StringPrinter(metaclass=StringPrinterMeta): 50 | """Печатающий класс""" 51 | string = 'hello world' 52 | number = 2 53 | -------------------------------------------------------------------------------- /python_pd/work/syntax/README.md: -------------------------------------------------------------------------------- 1 | # Практические работы к главе "Синтаксис" 2 | 3 | - [Игра FizzBuzz](fizzbuzz/description.md) 4 | 5 | [К содержанию](../../../README.md) 6 | -------------------------------------------------------------------------------- /python_pd/work/syntax/fizzbuzz/README.md: -------------------------------------------------------------------------------- 1 | # Игра FizzBuzz 2 | 3 | Игра на для обучения правилам делимости и простая задачка для проверки 4 | навыков программиста. 5 | 6 | # Описание 7 | 8 | Напишите программу, которая выводит на экран числа от 1 до n. При этом 9 | вместо чисел, кратных трем, программа должна выводить слово «Fizz», а 10 | вместо чисел, кратных пяти — слово «Buzz». Если число кратно и 3, и 5, 11 | то программа должна выводить слово «FizzBuzz». 12 | 13 | Число n вводится пользователем. 14 | 15 | Реализуйте две функции ```fizzbuzz(number)``` и ```main()```, см. 16 | шаблон в файле ```fizzbuzz.py```. Функция ```fizzbuzz(number)``` должна 17 | принимать целое число в качестве единственного параметра и печатать на 18 | экран последовательности чисел и строк, соответствующую задаче. 19 | Функция ```main()``` должна реализовывать считывание пользовательского 20 | ввода и проверку входных параметров. В случае некорректного ввода 21 | должно выводиться сообщение: "Введено некорректное значение". 22 | 23 | ### Входные данные 24 | 25 | - Целое число n, которое вводится пользователем с клавиатуры. 26 | 27 | ### Выходные данные 28 | 29 | В случае корректного ввода: 30 | - Последовательность из чисел и строк длиной n. Каждый элемент 31 | последовательности печатается на новой строке. 32 | 33 | В случае некорректного ввода (n не целое число или n < 1): 34 | - Сообщение об ошибке (без кавычек): "Введено некорректное значение". 35 | 36 | # Проверка решения 37 | 38 | Для проверки решения используйте тесты, они расположены в файле 39 | ```test_fizzbuzz.py```. Используйте команду для запуска: 40 | 41 | ```bash 42 | python -m unittest test_fizzbuzz.py 43 | ``` 44 | 45 | # Решение задачи 46 | 47 | Решение с комментариями расположено в файле ```solution.py```. 48 | 49 | Вы можете запустить его, выполнив команду: 50 | 51 | ```bash 52 | python solution.py 53 | ``` 54 | 55 | Для проверки решения можно запустить тесты следующей командой 56 | 57 | ```bash 58 | python -m unittest test_solution.py 59 | ``` 60 | 61 | Вы можете редактировать файл с решением и контролировать его 62 | правильность. 63 | 64 | # Ссылки 65 | 66 | - [Wiki](https://en.wikipedia.org/wiki/Fizz_buzz) 67 | - [Why Can't Programmers.. Program?](https://blog.codinghorror.com/why-cant-programmers-program/) 68 | -------------------------------------------------------------------------------- /python_pd/work/syntax/fizzbuzz/fizzbuzz.py: -------------------------------------------------------------------------------- 1 | def fizzbuzz(number): 2 | # разместите здесь реализацию основной логики программы. 3 | pass 4 | 5 | 6 | def main(): 7 | # разместите здесь проверку входных значений. 8 | pass 9 | 10 | 11 | if __name__ == '__main__': 12 | main() 13 | -------------------------------------------------------------------------------- /python_pd/work/syntax/fizzbuzz/solution.py: -------------------------------------------------------------------------------- 1 | """ 2 | Решение задачи FizzBuzz. 3 | См. описание в description.md. 4 | 5 | Содержит три варианта решения задачи: 6 | 1) check_number_v1 - наивное решение; 7 | 2) check_number_v2 - лаконичное решение; 8 | 3) check_number_v3 - короткое решение. 9 | """ 10 | 11 | 12 | def check_number_v1(number): 13 | """Проверка числа для игры FizzBuzz. 14 | Проверка на делимость "в лоб". Встречается повторяющийся код. 15 | :param number: проверяемое число. 16 | :type number: int 17 | :return: строка 'FizzBuzz', если число кратно 3 и 5, 18 | строку 'Fizz', если число кратно 3, 19 | строку 'Buzz', если число кратно 5, иначе само число. 20 | :rtype: int или str 21 | """ 22 | if number % 3 == 0 and number % 5 == 0: 23 | return 'FizzBuzz' 24 | elif number % 3 == 0: 25 | return 'Fizz' 26 | elif number % 5 == 0: 27 | return 'Buzz' 28 | else: 29 | return number 30 | 31 | 32 | def check_number_v2(number): 33 | """Проверка числа для игры FizzBuzz. 34 | Более лаконичное решение по сравнению с check_number_v1. 35 | :param number: проверяемое число. 36 | :type number: int 37 | :return: строка 'FizzBuzz', если число кратно 3 и 5, 38 | строку 'Fizz', если число кратно 3, 39 | строку 'Buzz', если число кратно 5, иначе само число. 40 | :rtype: int или str 41 | """ 42 | result = '' 43 | if number % 3 == 0: 44 | result += 'Fizz' 45 | if number % 5 == 0: 46 | result += 'Buzz' 47 | return result if result else number 48 | 49 | 50 | def check_number_v3(number): 51 | """Проверка числа для игры FizzBuzz. 52 | Короткая версия решения. Здесь используется свойство логического 53 | типа, а именно его эквивалентность 0 или 1. 54 | :param number: проверяемое число. 55 | :type number: int 56 | :return: строка 'FizzBuzz', если число кратно 3 и 5, 57 | строку 'Fizz', если число кратно 3, 58 | строку 'Buzz', если число кратно 5, иначе само число. 59 | :rtype: int или str 60 | """ 61 | result = 'Fizz' * (not number % 3) + 'Buzz' * (not number % 5) 62 | return result if result else number 63 | 64 | 65 | def fizzbuzz(number, version=1): 66 | """Игра FizzBuzz. 67 | :param number: верхняя граница (ключительно). 68 | :type number: int 69 | :param version: версия решения: 1 - наивное, 70 | 2 - лаконичное, 3 - короткое. 71 | :type version: int 72 | """ 73 | for i in range(1, number + 1): 74 | if version == 1: 75 | print(check_number_v1(i)) 76 | elif version == 2: 77 | print(check_number_v2(i)) 78 | else: 79 | print(check_number_v3(i)) 80 | 81 | 82 | def main(): 83 | n = input('Введите n: ') 84 | if n.isdigit() and int(n) >= 1: 85 | n = int(n) 86 | else: 87 | print('Введено некорректное значение') 88 | return 89 | 90 | version = input('Введите версию программы: ') 91 | if version.isdigit() and 1 <= int(version) <= 3: 92 | version = int(version) 93 | else: 94 | version = 1 95 | print('Введено некорректное значение. Используется значение 1') 96 | 97 | fizzbuzz(n, version) 98 | 99 | 100 | if __name__ == '__main__': 101 | main() 102 | -------------------------------------------------------------------------------- /python_pd/work/syntax/fizzbuzz/test_fizzbuzz.py: -------------------------------------------------------------------------------- 1 | from unittest import mock, TestCase, main 2 | 3 | if __package__: 4 | from . import fizzbuzz 5 | else: 6 | import fizzbuzz 7 | 8 | 9 | path = f'{__package__}{"." if __package__ else ""}fizzbuzz' 10 | 11 | 12 | def get_test_data(): 13 | return [ 14 | (1, ), (2, ), ('Fizz', ), (4, ), ('Buzz', ), ('Fizz', ), 15 | (7, ), (8, ), ('Fizz', ), ('Buzz', ), (11, ), ('Fizz', ), 16 | (13, ), (14, ), ('FizzBuzz', ) 17 | ] 18 | 19 | 20 | @mock.patch(path + '.print', create=True) 21 | @mock.patch(path + '.input', create=True) 22 | class FizzBuzzMainTests(TestCase): 23 | def setUp(self): 24 | self.errors_str = ('qwe', repr(''), '-1', '0', '000') 25 | self.expected_error = (('Введено некорректное значение', ), ) 26 | 27 | expected_results = get_test_data() 28 | self.expected = [ 29 | (s, expected_results[:i]) for i, s in enumerate(('1', '5', '15')) 30 | ] 31 | self.expected += [(s, self.expected_error) for s in self.errors_str] 32 | 33 | def test_main(self, mocked_input, mocked_print): 34 | for user_input, result in self.expected: 35 | with self.subTest(user_input=user_input, result=result): 36 | mocked_input.side_effect = user_input 37 | fizzbuzz.main() 38 | for call, res in zip(mocked_print.call_args_list, result): 39 | self.assertEqual(call.args, res) 40 | mocked_input.reset_mock() 41 | mocked_print.reset_mock() 42 | 43 | 44 | @mock.patch(path + '.print', create=True) 45 | class FizzBuzzTests(TestCase): 46 | def setUp(self): 47 | self.errors_number = (-1, 0) 48 | 49 | expected_results = get_test_data() 50 | self.test_data = [(i, expected_results[:i]) for i in [1, 2, 3, 5, 15]] 51 | 52 | def test_fizzbuzz(self, mocked_print): 53 | for number, expected in self.test_data: 54 | with self.subTest(number=number): 55 | fizzbuzz.fizzbuzz(number) 56 | for call, res in zip(mocked_print.call_args_list, expected): 57 | self.assertEqual(call.args, res) 58 | mocked_print.reset_mock() 59 | 60 | def test_exception(self, mocked_print): 61 | for number in self.errors_number: 62 | with self.subTest(number=number): 63 | fizzbuzz.fizzbuzz(number) 64 | self.assertFalse(mocked_print.called) 65 | 66 | 67 | if __name__ == '__main__': 68 | main() 69 | -------------------------------------------------------------------------------- /python_pd/work/syntax/fizzbuzz/test_solution.py: -------------------------------------------------------------------------------- 1 | from itertools import product 2 | from unittest import mock, TestCase, main 3 | 4 | if __package__: 5 | from . import solution 6 | else: 7 | import solution 8 | 9 | 10 | path = f'{__package__}{"." if __package__ else ""}solution' 11 | 12 | 13 | @mock.patch(path + '.print', create=True) 14 | @mock.patch(path + '.input', create=True) 15 | class FizzBuzzSolutionTests(TestCase): 16 | def setUp(self): 17 | self.versions = ('1', '2', '3') 18 | 19 | expected_results = [ 20 | (1, ), (2, ), ('Fizz', ), (4, ), ('Buzz', ), ('Fizz', ), 21 | (7, ), (8, ), ('Fizz', ), ('Buzz', ), (11, ), ('Fizz', ), 22 | (13, ), (14, ), ('FizzBuzz', ) 23 | ] 24 | self.expected = [ 25 | (s, expected_results[:i]) for i, s in enumerate(('1', '5', '15')) 26 | ] 27 | 28 | self.errors_str = ('qwe', repr(''), '-1', '0', '000') 29 | self.expected_error = ('Введено некорректное значение', ) 30 | 31 | def test_main(self, mocked_input, mocked_print): 32 | for (user_input, result), v in product(self.expected, self.versions): 33 | with self.subTest(user_input=user_input, version=v, result=result): 34 | mocked_input.side_effect = [user_input, v] 35 | solution.main() 36 | for call, res in zip(mocked_print.call_args_list, result): 37 | self.assertEqual(call.args, res) 38 | mocked_input.reset_mock() 39 | mocked_print.reset_mock() 40 | 41 | def test_main_errors(self, mocked_input, mocked_print): 42 | for user_input in self.errors_str: 43 | with self.subTest(user_input=user_input): 44 | mocked_input.side_effect = user_input 45 | solution.main() 46 | self.assertEqual(mocked_print.call_args.args, 47 | self.expected_error) 48 | mocked_input.reset_mock() 49 | mocked_print.reset_mock() 50 | 51 | 52 | if __name__ == '__main__': 53 | main() 54 | --------------------------------------------------------------------------------