Python – это просто. Пошаговое руководство по программированию и анализу данных_1
Текст
                    PYTHON—
это просто
Пошаговое руководство
по программированию
и анализу данных

■ Исследуйте возможности Python
с использованием дистрибутива
Anaconda
■ Узнайте, как установит^.
и использовать Python на своем
компьютере
■ Создавайте свои переменные,
объекты и изучите их синтаксис
■ Изучите встроенные типы объектов
Python, такие как строки, списки,
кортежи, множества и словари
■ Научитесь вызывать встроенные
функции, а также писать свои
собственные
■ Организуйте свой код и другие
объекты в более крупные
компоненты с помощью модулей
■ Исследуйте классы — инструмент
объектно-ориентированного
программирования
■ Пишите сложный код, научитесь
обрабатывать ошибки и исключения
■ Узнайте о массивах NumPy
и операциях с ними
■ Изучите анализ данных с помощью
Pandas
■ Погрузитесь в захватывающий мир
визуализации с использованием
Matplotlib
■ Научитесь создавать приложения
Python с графическим
интерфейсом

Изучите программирование
на Python, начиная с самых основ
и заканчивая использованием би­
блиотек для анализа данных и визуа­
лизации. Эта книга поможет освоить
Python как абсолютным новичкам,
так и опытным программистам,
знакомым с другими языками. В нее
включены все актуальные на сегод­
няшний день расширения Python.

д
s
Ci

Л

S3

Нилаб Нисчал имеет
степень магистра
менеджмента, работает
штатным специалистом
по маркетингу и ведущим
аналитиком данных на протяжении
более 14 лет. Он обучает студентов
колледжей как в инженерной
области, так и в области управления.
Страсть к принятию осмысленных
бизнес-решений на основе анализа
данных привела его к глубокому
изучению языков R и Python.
Результатом данных изысканий
и стала эта книга.

PYTHON —
это просто
Пошаговое руководство
по программированию
и анализу данных

191036, Санкт-Петербург,
Гончарная уп„ 20
Тел.: (812) 717-10-50,
339-54-17, 339-54-28
E-mail: mail@bhv.ru
Internet: www.bhv.ru

Нилаб Нисчал

%


PYTHON MADE EASY Step by Step Guide to Programming and Data Analysis using Python for Beginners and Intermediate Level NILABH NISHCHHAL
Нилаб Нисчал PYTHON это просто Пошаговое руководство по программированию и анализу данных Санкт-Петербург «БХВ-Петербург» 2023
УДК 004.43 ББК 32.973-018.1 Н69 Нисчал Н. Н69 Python — это просто. Пошаговое руководство по программированию и анализу данных: Пер. с англ. — СПб.: БХВ-Петербург, 2023. — 416 с.: ил. ISBN 978-5-9775-6849-4 Рассмотрены основы синтаксиса языка Python на примере дистрибутива Anaconda. Показаны приложения IPython, Spyder IDE, Jupyter Notebook. Описан синтаксис переменных, функций, циклов. Подробно изучаются структуры данных в Python: строки, списки, кортежи, множества и словари. Объясняется понятие классов и их применение в объектно-ориентированном программировании. Описа­ ны возможности библиотеки обработки изображений Pillow, библиотеки Tkinter для создания приложений с графическим интерфейсом. Отдельный раздел посвя­ щен обработке ошибок и исключений в программах. Рассматриваются библиотеки NumPy и Pandas, приводятся практические примеры их использования для анализа и обработки данных. Описана библиотека Matplotlib и ее возможности в сфере визуализации данных. Для программистов УДК 004.43 ББК 32.973-018.1 Группа подготовки издания: Руководитель проекта Зав. редакцией Перевод с английского Компьютерная верстка Оформление обложки Павел Шалив Людмила Гауль Кристины Черниковой Ольги Сергиенко Зои Канторович Copyright © 2021 by Nilabh Nishchhal Translation Copyright © 2022 by BHV. All rights reserved. Перевод © 2022 BHV Все права защищены. Подписано в печать 03.10.22. Формат 70x1001/16. Печать офсетная. Усл. печ. л. 33,54. Доп. тираж 1500 экз. Заказ № 5396. "БХВ-Петербург", 191036, Санкт-Петербург, Гончарная ул., 20 Отпечатано с готового оригинал-макета ООО "Принт-М", 142300, МО., г. Чехов, ул. Полиграфистов, д. 1 ISBN 978-1-64983-725-7 (англ.) ISBN 978-5-9775-6849-4 (рус.) © Nilabh Nishchhal, 2021 © Перевод на русский язык, оформление. ООО "БХВ-Петербург”, ООО "БХВ", 2022, 2023
Оглавление Предисловие................................................................................................................... 19 О книге.....................................................................................................................................................19 Как получить максимум от этой книги.............................................................................................. 19 Структура книги.................................................................................................................................... 20 Об авторе......................................................................................................................... 23 Благодарности................................................................................................................ 27 Глава 1. Введение в Data Science и основы программирования.......................... 29 1.1. Введение в Data Science............................................................................................................. 29 1.1.1. Зачем нам Data Science?...................................................................................................... 30 1.1.2. История Data Science............................................................................................................ 31 1.1.2.1. Данные в древности................................................................................................... 31 1.1.2.2. Появление статистики................................................................................................ 32 1.1.2.3. Зарождение современного хранения данных......................................................... 32 1.1.2.4. Появление больших центров обработки данных.................................................. 33 1.1.2.5. Появление Интернета................................................................................................. 33 1.1.3. Настоящее и будущее Data Science................................................................................... 34 1.1.4. Чем занимается специалист по Data Science?................................................................. 35 1.1.5. Как это делается?.................................................................................................................. 35 1.1.6. Предпосылки для Data Science...........................................................................................35 1.1.7. Профессии в области Data Science.................................................................................... 36 1.2. От Data Science к программированию.................................................................................... 37 1.3. Основы компьютерного программирования.......................................................................... 38 1.3.1. Что такое программирование?............................................................................................ 38 1.3.2. Компьютерный алгоритм.................................................................................................... 39 1.3.2.1. Последовательные операторы.................................................................................. 40 1.3.2.2. Условные операторы.................................................................................................. 41 1.3.2.3. Цикл или итерации..................................................................................................... 41 1.3.3. Блок-схемы............................................................................................................................. 41 1.3.4. Что такое язык программирования?................................................................................. 42 1.3.5. Что такое исходный код?.................................................................................................... 44 1.3.6. Как запустить исходный код?............................................................................................. 45 1.3.7. Компилятор............................................................................................................................ 45 1.3.8. Интерпретатор...................................................................................................................... 46 1.3.8.1. Сравнение компилятора и интерпретатора............................................................ 47 1.3.9. Что такое интегрированная среда разработки (IDE)?................................................... 47 1.3.10. Spyder IDE............................................................................................................................ 48 1.4. Резюме........................................................................................................................................... 49
6 | Оглавление 1.5. Упражнения.................................................................................................................................. 49 1.5.1. Ответьте на вопросы............................................................................................................. 49 1.5.2. Правда или ложь.................................................................................................................... 49 1.5.3. Практические задания........................................................................................................... 50 1.5.4. Изучите самостоятельно...................................................................................................... 50 Глава 2. Введение в Python........................................................................................... 51 2.1. Что такое Python?....................................................................................................................... 51 2.1.1. Почему именно Python?........................................................................................................51 2.1.2. Появление Python.................................................................................................................. 52 2.1.3. Python и другие языки программирования....................................................................... 53 2.1.4. Философия Python................................................................................................................. 55 2.2. Преимущества Python по сравнению с другими языками................................................... 55 2.2.1. Простота.................................................................................................................................. 55 2.2.2. Легкость в изучении.............................................................................................................. 55 2.2.3. Свободный и открытый исходный код.............................................................................. 55 2.2.4. Высокоуровневость............................................................................................................... 56 2.2.5. Портативность........................................................................................................................ 56 2.2.6. Интерпретируемость............................................................................................................. 56 2.2.7. Интерпретаторы Python....................................................................................................... 56 2.2.7.1. IPython............................................................................................................................ 57 2.2.7.2. CPython........................................................................................................................... 57 2.2.7.3. IronPython....................................................................................................................... 58 2.2.7.4. Jython.............................................................................................................................. 58 2.2.7.5. PyPy................................................................................................................................ 58 2.2.7.6. PythonNet........................................................................................................................59 2.2.7.7. Stackless Python............................................................................................................. 59 2.2.8. Объектная ориентированность............................................................................................ 59 2.2.9. Расширяемость........................................................................................................................60 2.2.10. Встраиваемость.................................................................................................................... 60 2.2.11. Внушительные библиотеки............................................................................................... 60 2.2.12. Python для начинающих..................................................................................................... 61 2.3. Версии Python............................................................................................................................... 62 2.3.1. Python 2..................................................................................................................................... 62 2.3.2. Python 2.7..................................................................................................................................62 2.3.3. Python 3..................................................................................................................................... 62 2.3.4. Ключевые отличия версий................................................................................................... 63 2.4. Как установить и использовать Python.................................................................................... 63 2.4.1. Дистрибутив Anaconda.......................................................................................................... 63 2.4.2. Почему именно Anaconda?.................................................................................................. 64 2.4.3. Установка Anaconda в Windows..........................................................................................64 2.4.4. Установка Anaconda в MacOS............................................................................................. 68 2.5. Запуск Python через командную строку.................................................................................. 71 2.6. Приложения Anaconda................................................................................................................ 73 2.7. Консоль IPython Qt.......................................................................................................................73 2.8. Spyder IDE...................................................................................................................................... 75 2.8.1. Компоненты Spyder IDE.......................................................................................................76 2.8.1.1. Редактор текста............................................................................................................. 76 2.8.1.2. IPython консоль............................................................................................................. 77 2.8.1.3. Обозреватель переменных...................................................................................... ...77 2.8.1.4. Справка........................................................................................................................... 79
Оглавление | 7 2.9. Jupyter Notebook.......................................................................................................................... 80 2.9.1. Приложение Jupyter Notebook............................................................................................80 2.9.2. Основные возможности веб-приложения.........................................................................80 2.9.3. Документы Notebook............................................................................................................80 2.9.4. Запуск сервера Notebook..................................................................................................... 81 2.9.5. Создание нового документа Notebook.............................................................................. 82 2.9.6. Открытие документа Notebook........................................................................................... 82 2.9.7. Интерфейс документа Notebook......................................................................................... 82 2.9.8. Структура документа Notebook.......................................................................................... 83 2.9.9. Ячейки кода............................................................................................................................83 2.9.10. Ячейки Markdown............................................................................................................... 83 2.9.11. Неформатированные ячейки............................................................................................. 84 2.9.12. Рабочий процесс................................................................................................................. 84 2.9.13. Горячие клавиши................................................................................................................ 84 2.9.14. Построение графиков.........................................................................................................85 2.9.15. Совместимость с браузерами............................................................................................ 85 2.10. Что лучше использовать?........................................................................................................ 85 2.11. Резюме......................................................................................................................................... 86 2.12. Упражнения................................................................................................................................ 87 2.12.1. Ответьте на вопросы..........................................................................................................87 2.12.2. Правда или ложь................................................................................................................. 87 2.12.3. Изучите самостоятельно................................................................................................... 88 Глава 3. Основы Python............................................................................................... 89 3.1. Запуск Python............................................................................................................................... 89 3.1.1. Использование Spyder IDE................................................................................................. 89 3.1.2. Использование Jupyter Notebook........................................................................................91 3.2. Начнем с «Hello World!»............................................................................................................92 3.3. Использование Python как калькулятора................................................................................ 93 3.3.1. Числа....................................................................................................................................... 93 3.3.2. Строки..................................................................................................................................... 94 3.3.2.1. Конкатенация и повторение..................................................................................... 95 3.3.2.2. Индексирование...........................................................................................................95 3.3.2.3. Срезы............................................................................................................................. 96 3.4. Синтаксис кода Python............................................................................................................... 97 3.4.1. Выражения............................................................................................................................. 97 3.4.1.1. Окончание выражений............................................................................................... 98 3.4.2. Переменные и присваивание значений........................................................................ 99 3.4.3. Имена переменных и ключевые слова.............................................................................. 99 3.4.4. Выполнение выражений....................................................................................................100 3.5. Первые шаги в программировании........................................................................................ 101 3.5.1. Подробнее о функции print().......................................................................................102 3.5.2. Форматированный вывод...................................................................................................104 3.5.3. Простейшая геометрия иprint()..................................................................................104 3.6. Поиск ошибок............................................................................................................................ 105 3.6.1. Синтаксические ошибки....................................................................................................105 3.6.2. Ошибки времени выполнения.......................................................................................... 106 3.6.3. Семантические ошибки...................................................................................................... 106 3.6.4. Когда никакие средства не помогают.............................................................................. 107 3.7. Резюме......................................................................................................................................... 108
8 | Оглавление 3.8. Упражнения.................................................................................................................................. 108 3.8.1. Ответьте на вопросы........................................................................................................... 108 3.8.2. Правда или ложь...................................................................................................................108 3.8.3. Практические задания......................................................................................................... 109 3.8.4. Изучите самостоятельно.................................................................................................... 110 Глава 4. Объекты и операторы в Python................................................................. Ill 4.1. Переменные.................................................................................................................................111 4.1.1. Оператор присваивания...................................................................................................... 112 4.1.2. Имена переменных.............................................................................................................. 112 4.2. Структура программы............................................................................................................... 112 4.3. Объекты........................................................................................................................................ 113 4.3.1. Классификация объектов....................................................................................................113 4.3.2. Преимущества встроенных типов.....................................................................................114 4.3.3. Идентификаторы, значения и типы объектов................................................................ 116 4.3.4. Изменяемые и неизменяемые объекты............................................................................ 117 4.4. Стандартная иерархия типов.................................................................................................... 117 4.4.1. Встроенные константы........................................................................................................ 118 4.4.2. Числовые типы...................................................................................................................... 118 4.4.3. Последовательности............................................................................................................ 119 4.4.3.1. Неизменяемые последовательности....................................................................... 119 4.4.3.2. Изменяемые последовательности........................................................................... 121 4.4.4. Множества............................................................................................................................. 121 4.4.5. Сопоставления...................................................................................................................... 122 4.4.6. Вызываемые типы............................................................................................................... 122 4.4.7. Модули................................................................................................................................... 123 4.5. Операции с объектами в Python.............................................................................................. 124 4.6. Операторы.................................................................................................................................... 124 4.6.1. Арифметические операторы.............................................................................................. 125 4.6.2. Операторы присваивания....................................................................................................126 4.6.3. Операторы сравнения.......................................................................................................... 127 4.6.4. Логические операторы........................................................................................................ 128 4.6.5. Операторы идентификации и вхождения........................................................................ 128 4.7. Отступы........................................................................................................................................ 129 4.8. Комментарии в Python............................................................................................................... 130 4.9. Порядок выполнения..................................................................................................................130 4.9.1. Изменение порядка выполнения................................................................................... ...131 4.9.2. Ассоциативность..................................................................................................................131 4.9.3. Площадь прямоугольника...................................................................................................132 4.10. Динамическая типизация........................................................................................................ 132 4.11. Строгая типизация.................................................................................................................... 133 4.12. Логическая и физическая строка........................................................................................... 133 4.13. Резюме........................................................................................................................................ 134 4.14. Упражнения................................................................................................................................134 4.14.1. Ответьте на вопросы......................................................................................................... 134 4.14.2. Правда или ложь................................................................................................................. 135 4.14.3. Практические задания....................................................................................................... 135 4.14.4. Изучите самостоятельно................................................................................................... 136
Оглавление | 9 Глава 5. Операторы управления потоком.............................................................. 137 5.1. Управление потоком................................................................................................................ 137 5.2. Операторы if........................................................................................................................ 137 5.2.1. Простой оператор if..................................................................................................... 137 5.2.2. Оператор if-else............................................................................................................. 139 5.2.3. Оператор if-elif-else..................................................................................................... 140 5.3. Оператор цикла /ог.................................................................................................................... 142 5.3.1. Цикл for с блоком else.................................................................................................. 143 5.4. Функция rangeQ.................................................................................................................. 144 5.5. Цикл while...........................................................................................................................145 5.6. Операторы break и continue...............................................................................................146 5.6.1. Оператор break..............................................................................................................146 5.6.2. Оператор continue.........................................................................................................148 5.7. Оператор pass......................................................................................................................149 5.8. Резюме......................................................................................................................................... 150 5.9. Упражнения................................................................................................................................ 150 5.9.1. Ответьте на вопросы.......................................................................................................... 150 5.9.2. Правда или ложь..................................................................................................................151 5.9.3. Практические задания........................................................................................................ 152 Глава 6. Функции........................................................................................................ 153 6.1. Определение функций.............................................................................................................. 153 6.2. Типы функций............................................................................................................................ 153 6.3. Встроенные функции............................................................................................................... 154 6.3.1. Описание некоторых встроенных функций...................................................................154 6.4. Пользовательские функции..................................................................................................... 156 6.4.1. Зачем создавать функции?................................................................................................ 156 6.4.2. Создание и вызов функций............................................................................................... 157 6.4.3. Входные параметры и аргументы....................................................................................158 6.4.3.1. Параметры...................................................................................................................159 6.4.3.2. Аргументы...................................................................................................................160 6.4.3.3. Количество аргументов............................................................................................ 161 6.4.4. Возврат значений из функций.......................................................................................... 162 6.5. Варианты передачи аргументов..............................................................................................164 6.5.1. Аргументы со значением по умолчанию........................................................................ 164 6.5.2. Произвольное число аргументов (fargs).................................................................... 164 6.5.3. Именованные аргументы...................................................................................................165 6.5.4. Произвольное число именованных аргументов (**kwargs)......................................166 6.6. Генераторы................................................................................................................................. 167 6.6.1. Определение генератора....................................................................................................167 6.6.2. Пояснение к примеру......................................................................................................... 168 6.7. Резюме......................................................................................................................................... 168 6.8. Упражнения.................................................................................................................................169 6.8.1. Ответьте на вопросы.......................................................................................................... 169 6.8.2. Правда или ложь..................................................................................................................169 6.8.3. Практические задания................................................................. 169 6.8.4. Изучите самостоятельно....................................................................................................170 Глава 7. ПРОЕКТ 1: Рисунки из символов с помощью циклов и функций...... 171 7.1. Рисунки с помощью символа * (звездочка)......................................................................... 171 7.1.1. Прямоугольный треугольник........................................................................................... 171
10 | Оглавление 7.1.2. Перевернутый прямоугольный треугольник.................................................................. 172 7.1.3. Равносторонний треугольник............................................................................................ 174 7.1.4. Прямоугольный треугольник вверх ногами................................................................... 175 7.1.5. Стрелка вправо...................................................................................................................... 175 7.1.6. Практические задания......................................................................................................... 176 7.2. Рисунки с помощью цифр......................................................................................................... 177 7.2.1. Прямоугольный треугольник............................................................................................ 177 7.2.2. Прямоугольный треугольник 2......................................................................................... 177 7.2.3. Прямоугольный треугольник вверх ногами................................................................... 178 7.2.4. Треугольник из обратных чисел........................................................................................ 179 7.2.5. Треугольник из квадратов обратных чисел.................................................................... 179 7.2.6. Ромб........................................................................................................................................ 179 7.2.7. Ромб с другим направлением чисел..................................................................................181 7.2.8. Стрелка влево........................................................................................................................ 182 7.2.9. Практические задания......................................................................................................... 183 7.3. Резюме...........................................................................................................................................184 Глава 8. Структуры данных и последовательности.............................................. 185 8.1. Строки............................................................................................................................................185 8.1.1. Строковые операции........................................................................................................... 186 8.1.2. Форматирование................................................................................................................... 187 8.1.3. Методы split() и joinQ.................................................................................................... 188 8.2. Списки........................................................................................................................................... 189 8.2.1. Индексы и срезы...................................................................................................................191 8.2.2. Методы списков.................................................................................................................... 192 8.2.3. Списковые включения........................................................................................................ 193 8.2.4. Оператор del................................................................................................................... 194 8.3. Кортежи........................................................................................................................................ 195 8.3.1. Методы кортежей................................................................................................................. 196 8.4. Множества.................................................................................................................................... 196 8.4.1. Операции над множествами.............................................................................................. 197 8.4.2. Методы множеств.................................................................................................................198 8.5. Словари......................................................................................................................................... 199 8.5.1. Методы словарей................................................................................................................. 200 8.6. Перебор последовательностей в цикле............................................................................. 201 8.7. Резюме.......................................................................................................................................... 202 8.8. Упражнения................................................................................................................................. 202 8.8.1. Ответьте на вопросы...........................................................................................................202 8.8.2. Правда или ложь.................................................................................................................. 203 8.8.3. Практические задания.........................................................................................................203 8.8.4. Изучите самостоятельно................................................................................ 204 Глава 9. Ввод-вывод данных и работа с файлами................................................ 205 9.1. Ввод данных................................................................................................................................ 205 9.2. Форматированный вывод данных...........................................................................................207 9.2.1. Форматированные строки.................................................................................................. 207 9.2.2. Строковый метод/оглга/(9.................................................................................................. 208 9.2.3. Форматирование строк вручную...................................................................................... 210 9.2.4. Функции str() и герг()................................................................................................... 211 9.2.5. Старое форматирование строки....................................................................................... 212
Оглавление | 11 9.3. Чтение и запись файлов.......................................................................................................... 212 9.3.1. Методы файловых объектов............................................................................................ 213 9.3.2. Создание файла и запись в него...................................................................................... 214 9.3.3. Открытие файла и чтение его содержимого................................................................. 215 9.3.4. Построчное чтение.............................................................................................................215 9.3.5. Чтение и запись нетекстовых файлов............................................................................. 216 9.4. Резюме.........................................................................................................................................216 9.5. Упражнения................................................................................................................................ 216 9.5.1. Ответьте на вопросы......................................................................................................... 216 9.5.2. Правда или ложь................................................................................................................. 217 9.5.3. Практические задания....................................................................................................... 217 9.5.4. Изучите самостоятельно................................................................................................... 218 Глава 10. ПРОЕКТ 2: Автоматизация обработки множества изображений..... 219 10.1. 10.2. 10.3. 10.4. 10.5. 10.6. 10.7. Изменение типа файла (расширения)................................................................................. 221 Изменение размеров фотографий........................................................................................223 Преобразование изображений в черно-белые................................................................... 223 Поворот изображений............................................................................................................ 224 Изменение разрешения изображения................................................................................. 225 Резюме...................................................................................................................................... 226 Изучите самостоятельно....................................................................................................... 226 Глава 11. Классы......................................................................................................... 227 11.1. Основные понятия.................................................................................................................. 227 11.1.1. Введение в объектно-ориентированное программирование................................... 227 11.1.2. Введение в понятие класса.............................................................................................229 11.2. Объект класса...........................................................................................................................229 11.2.1. Метод init ............................................................................................................ 230 11.3. Объекты экземпляров.............................................................................................................231 11.3.1. Создание экземпляров класса......................................................................................... 231 11.3.2. Как это работает............................................................................................................... 232 11.3.3. Пример использования экземпляров класса............................................................... 232 11.4. Объекты методов.................................................................................................................... 234 11.5. Наследование........................................................................................................................... 235 11.6. Множественное наследование.............................................................................................. 236 11.6.1. Переопределение методов.............................................................................................. 239 11.7. Полиморфизм...........................................................................................................................241 11.8. Абстракция и инкапсуляция........................................................................................... 241 11.9. Как контролировать доступ.................................................................................................. 242 11.9.1. Приватные переменные.................................................................................................. 242 11.10. Резюме.................................................................................................................................... 243 11.11. Упражнения............................................................................................................................243 11.11.1. Ответьте на вопросы..................................................................................................... 243 11.11.2. Правда или ложь.............................................................................................................243 11.11.3. Практические задания................................................................................................... 244 11.11.4. Изучите самостоятельно............................................................................................... 245 Глава 12. Ошибки и обработка исключений......................................................... 247 12.1. Ошибки и исключения........................................................................................................... 247 12.1.1. Синтаксические ошибки................................................................................................. 247 12.1.2. Исключения....................................................................................................................... 248
12 | Оглавление 12.2. Вызов исключений.................................................................................................................. 249 12.2.1. Оператор raise............................................................................................................. 249 12.2.2. Исключение AssertionError........................................................................................ 250 12.3. Обработка исключений........................................................................................................... 251 12.3.1. Операторы try и except............................................................................................... 251 12.3.2. Блок else........................................................................................................................252 12.4. Завершающий блок.................................................................................................................. 253 12.5. Резюме........................................................................................................................................ 255 12.6. Упражнения............................................................................................................................... 255 12.6.1. Ответьте на вопросы.........................................................................................................255 12.6.2. Правда или ложь................................................................................................................ 255 12.6.3. Практические задания...................................................................................................... 256 Глава 13. Модули и пакеты........................................................................................ 257 13.1. Модули....................................................................................................................................... 257 13.1.1. Определение модуля.........................................................................................................257 13.1.2. Подробнее о модулях........................................................................................................259 13.2. Импорт модулей.......................................................................................................................259 13.2.1. Импорт модулей из других модулей.............................................................................. 259 13.2.2. Импорт имен из модуля напрямую................................................................................ 260 13.2.3. Импорт всех имен из модуля...........................................................................................260 13.2.4. Импорт модуля под другим именем.............................................................................. 260 13.3. Стандартные модули............................................................................................................... 261 13.4. Функция dir().....................................................................................................................262 13.5. Пакеты........................................................................................................................................ 263 13.5.1. Пример пакета sound................................................................................................. 263 13.5.2. Вызов пакета для дальнейшего использования.......................................................... 265 13.5.3. Популярные пакеты в Python...........................................................................................266 13.5.3.1. Сбор данных.............................................................................................................. 266 13.5.3.2. Обработка данных и моделирование................................................................... 266 13.5.3.3. Визуализация данных.............................................................................................. 268 13.6. Резюме........................................................................................................................................ 269 13.7. Упражнения............................................................................................................................... 269 13.7.1. Ответьте на вопросы......................................................................................................... 269 13.7.2. Правда или ложь................................................................................................................ 269 13.7.3. Изучите самостоятельно.................................................................................................. 270 Глава 14. ПРОЕКТ 3: Конвертер валют с графическим интерфейсом............ 271 14.1. Введение в Tkinter................................................................................................................... 271 14.2. Основные шаги в Tkinter.........................................................................................................273 14.3. Окно интерфейса конвертера валют.................................................................................... 274 14.3.1. Использование методараск().................................................................................... 275 14.3.2. Использование метода grid()..................................................................................... 276 14.4. Код для конвертации валют................................................................................................... 277 14.5. Итоговое приложение............................................................................................................. 279 14.6. Резюме........................................................................................................................................ 282 14.7. Изучите самостоятельно.........................................................................................................282 Глава 15. Библиотека NumPy..................................................................................... 283 15.1. Введение в NumPy......................................................................... 283 15.1.1. Установка NumPy.............................................................................................................. 284
Оглавление | 13 15.1.2. Импорт NumPy............................................................................................... 284 15.1.3. Разница между списком Python и массивом NumPy................................................. 284 15.1.4. Зачем нам NumPy?............................................................................................................285 15.2. Массив NumPy........................................................................................................................ 286 15.2.1. Размерность массива....................................................................................................... 286 15.2.2. Другие атрибуты массива............................................................................................... 287 15.3. Создание массива................................................................................................................... 287 15.3.1. Массивы из нулей, единиц и случайных чисел.......................................................... 289 15.3.2. Массив из диапазона значений.......................................................................................290 15.3.3. Указание типа данных массива..................................................................................... 291 15.3.4. Вывод массивов................................................................................................................ 291 15.4. Сортировка, добавление и удаление элементов массива................................................ 292 15.4.1. Сортировка........................................................................................................................ 292 15.4.2. Сложение (конкатенация)............................................................................................... 292 15.4.3. Удаление.............................................................................................................................293 15.5. Форма и размер массива....................................................................................................... 293 15.6. Изменение формы................................................................................................................... 294 15.7. Добавление оси....................................................................................................................... 295 15.8. Индексирование и срезы....................................................................................................... 296 15.9. Создание массива из существующих данных................................................................... 298 15.10. Копии и представления массивов..................................................................................... 299 15.10.1. Присваивание без копии............................................................................................... 300 15.10.2. Представление или неглубокая копия....................................................................... 300 15.10.3. Глубокая копия............................................................................................................... 301 15.11. Массивы NumPy в реальной жизни.................................................................................. 301 15.11.1. Электронные таблицы Excel......................................................................................... 302 15.11.2. Аудиофайлы и временные ряды.................................................................................. 302 15.11.3. Изображения................................................................................................................... 303 15.12. Резюме.....................................................................................................................................304 Глава 16. Операции в NumPy.................................................................................... 305 16.1. Основные операции над массивами.................................................................................... 305 16.1.1. Универсальные функции................................................................................................ 307 16.2. Транслирование...................................................................................................................... 308 16.3. Функции агрегирования........................................................................................................ 308 16.4. Двумерные массивы............................................................................................................... 309 16.5. Уникальные элементы массива............................................................................................311 16.6. Транспонирование и изменение формы матрицы............................................................ 313 16.7. Обратный порядок элементов массива............................................................................... 314 16.8. Сжатие многомерного массива в одномерный................................................................. 316 16.9. Работа с математическими формулами.............................................................................. 317 16.10. Сохранение массива в файл и чтение из файла.............................................................. 318 16.11. Резюме.....................................................................................................................................319 Глава 17. Библиотека Pandas.................................................................................... 321 17.1. Введение в Pandas................................................................................................................... 321 17.1.1. Зачем нам Pandas?............................................................................................................. 321 17.1.2. Установка и импорт Pandas............................................................................................ 322 17.1.3. Обработка данных в Pandas............................................................................................ 323
14 | Оглавление 17.2. Тип данных DataFrame.................................................................................................... 323 17.2.1. Создание DataFrame.................................................................................................. 323 17.2.2. Индексы в DataFrame................................................................................................ 324 17.2.3. Series в DataFrame...................................................................................................... 324 17.3. Столбцы DataFrame......................................................................................................... 325 17.3.1. Добавление столбца.......................................................................................................... 325 17.3.2. Удаление столбца.............................................................................................................. 326 17.3.3. Изменение значений в столбце....................................................................................... 326 17.4. Строки DataFrame............................................................................................................ 326 17.4.1. Выбор строки......................................................................................................................326 17.4.2. Срез строки (выбор нескольких строк)......................................................................... 327 17.5. Операции с DataFrame..................................................................................................... 327 17.6. Чтение данных из файла.........................................................................................................328 17.6.1. Пояснение к данным из примера.................................................................................... 329 17.7. Запись данных в файл............................................................................................................. 330 17.8. Проверка DataFrame........................................................................................................ 330 17.8.1. Атрибут dtypes................................................................................................................... 330 17.8.2. Метод infoQ..................................................................................................................331 17.8.3. Метод head()................................................................................................................ 332 17.8.4. Метод tail()....................................................................................................................332 17.9. Выбор части DataFrame................................................................................................... 333 17.9.1. Выбор столбцов................................................................................................................. 333 17.9.2. Выбор строк (фильтрация)............................................................................................... 334 17.9.3. Выбор строк и столбцов................................................................................................... 335 17.10. Резюме...................................................................................................................................... 337 Глава 18. Pandas в действии.......................................................................................339 18.1. Добавление столбца................................................................................................................. 339 18.2. Удаление столбцов.................................................................................................................. 340 18.3. Переименование столбцов..................................................................................................... 340 18.4. Сводная статистика................................................................................................................. 341 18.5. Группировка по категориям.................................................................................................. 342 18.6. Сортировка строк......................................................................................................................345 18.7. Объединение данных из нескольких таблиц...................................................................... 345 18.7.1. Объединение объектов..................................................................................................... 346 18.7.2. Объединение с использованием общего идентификатора........................................ 347 18.8. Резюме........................................................................................................................................ 350 Глава 19. Визуализация в Python..............................................................................351 19.1. Визуализация данных.............................................................................................................. 351 19.1.1. Важность визуализации данных..................................................................................... 351 19.1.2. Основы визуализации........................................................................................................351 19.1.3. Простой линейный график в Pandas.............................................................................. 352 19.1.4. Базовая диаграмма рассеяния..........................................................................................354 19.1.5. Другие виды графиков..................................................................................................... 355 19.1.6. Диаграмма размаха............................................................................................................ 357 19.1.7. Несколько графиков..........................................................................................................358 19.1.8. Сохранение графика.......................................................................................................... 358 19.2. Библиотеки для визуализации данных................................................................................ 359 19.2.1. Matplotlib............................................................................................................................. 359
Оглавление | 15 19.2.2. Seaborn................................................................................................................................ 360 19.2.3. ggplot................................................................................................................................... 361 19.2.4. Bokeh................................................................................................................................... 362 19.2.5. Folium................................................................................................................................. 362 19.2.6. Gleam.................................................................................................................................. 363 19.3. Резюме...................................................................................................................................... 364 Глава 20. Визуализация с помощью Matplotlib Pyplot......................................... 365 20.1. Введение и историческая справка........................................................................................365 20.2. Основные объкты Matplotlib................................................................................................. 366 20.2.1. Иерархия объектов Matplotlib......................................................................................... 368 20.2.2. Типы входных данных для графиков............................................................................ 369 20.3. Элементы рисунка.................................................................................................................. 369 20.3.1. Рисунок {Figure)............................................................................................................... 370 20.3.2. Графики {Axes)........................................................................................................... 371 20.3.3. Оси {Axis).................................................................................................................... 371 20.3.4. Объекты Artist............................................................................................................ 371 20.4. Два способа использования Matplotlib............................................................................... 371 20.4.1. Объектно-ориентированный интерфейс.......................................................................371 20.4.2. Интерфейс Pyplot.............................................................................................................. 372 20.4.3. Так какой же способ лучше?.......................................................................................... 373 20.5. Построение схожих графиков с помощью функций....................................................... 373 20.6. Модуль Pyplot......................................................................................................................... 375 20.7. Функция plot().................................................................................................................. 376 20.7.1. Построение индексированных данных........................................................................ 377 20.7.2. Построение нескольких наборов данных.................................................................... 377 20.7.3. Форматирование стиля.................................................................................................... ЗТ1 20.8. Параметры функцииplot().............................................................................................. 379 20.8.1. Параметры х, у........................................................................................................... 379 20.8.2. Строка формата {fmt)................................................................................................. 379 20.8.2.1. Маркеры................................................................................................................... 379 20.8.2.2. Стили линий............................................................................................................. 380 20.8.2.3. Цвета..........................................................................................................................380 20.8.3. Данные {data).................................................................................................................... 380 20.9. Возвращаемый объектplotf)........................................................................................... 381 20.10. Именованные аргументы {**kwargs)........................................................................... 381 20.11. Построение графиков по меткам....................................................................................... 382 20.12. Построение графиков с категориальными переменными............................................. 383 20.13. Изменение свойств линии................................................................................................... 383 20.14. Работа с несколькими рисунками и графиками.............................................................. 384 20.15. Вставка текста на график.................................................................................................... 386 20.16. Использование математических выражений в тексте................................................... 387 20.16.1. Аннотирование текста................................................................................................... 387 20.17. Логарифмические и другие нелинейные оси.................................................................. 388 20.18. Резюме.................................................................................................................................... 390 Глава 21. Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib.............................................................................................391 21.1. Сравнение объектно-ориентированного API и Pyplot API............................................. 391 21.2. Данные для работы................................................................................................................. 392
16 | Оглавление 21.3. Построение графика по умолчанию..................................................................................... 392 21.4. Управление стилями................................................................................................................ 393 21.5. Разные настройки графика..................................................................................................... 394 21.6. Добавление элементов на график.......................................................................................... 397 21.7. Форматирование текста на графике..................................................................................... 398 21.7.1. Базовые команды для работы с текстом....................................................................... 399 21.8. Сохранение графика в файл................................................................................................... 401 21.9. Примеры графиков.................................................................................................................. 402 21.9.1. Гистограмма....................................................................................................................... 402 21.9.2. Кривые и ломаные линии................................................................................................. 403 21.9.3. Трехмерные графики........................................................................................................ 404 21.9.4. Круговая диаграмма......................................................................................................... 405 21.9.5. Пример построения нескольких графиков................................................................... 407 21.10. Резюме..................................................................................................................................... 407 Ответы на вопросы «Правда или ложь»..................................................................409 Библиография............................................................................................................... 411
Посвящение Книга посвящается Прабхе, моему первому учителю. Сарасвати, моей маме. Сунаяне, которую все называли Лакшми. Она словно отражение Сарасвати. Себя же посвящаю Маа Шарде... чтРНт
Предисловие О книге Эта книга представляет собой введение в программирование и анализ данных, а в качестве языка, на котором мы будем изучать материал, выбран любимый нович­ ками Python. По ходу книги мы узнаем, как установить на свой компьютер Python и необходимое программное обеспечение, как написать программу на Python и как создать собственное полноценное приложение с помощью языка программирова­ ния Python. Кроме того, мы подробно поговорим о библиотеках Python, которые используются в задачах анализа и визуализации данных, таких как NumPy, Pandas и Matplotlib. Также мы познакомимся и с другими библиотеками, например библио­ текой для редактирования изображений Pillow, библиотекой для создания графиче­ ских интерфейсов Tkinter и библиотекой OS, предназначенной для организации взаимодействия программы с операционной системой. Цель книги состоит в том, чтобы дать вам базовые знания Python, а для закрепления полученных знаний мы будем рассматривать решение реальных задач с использованием языка Python. Как получить максимум от этой книги В этой книге я использую активный подход к обучению. Книга ориентирована на новичков, не имеющих никакого опыта программирования. Следовательно, мы начнем с самого начала и первым делом установим программное обеспечение, ко­ торое будем использовать в книге. После этого советую вам самим поискать другие варианты программного обеспечения, которое может использоваться для работы с Python. Я предпочитаю работать в Jupyter Notebook и настоятельно рекомендую именно это приложение. После этого мы начнем изучать основы языка Python шаг за шагом, используя про­ стые и наглядные примеры кода. Вы познакомитесь с тем, как добавлять коммента­ рии, которые интерпретатор обрабатывает как «не связанные с кодом примечания». По ходу изучения материала книги всегда держите перед собой открытую среду Jupyter Notebook, т. к. это позволит вам сразу же практиковаться в написании кода и получить уверенное представление об основах языка. Ничто так не стимулирует обучение, как живой результат на собственном компьютере. Все примеры кода, ис­ пользованные в этой книге, я загрузил в свой репозиторий на GitHub для вашего ознакомления: https://github.com/nilabhnishchhal/Python-Made-Easy. В конце каждой главы приведен блок вопросов по теории, проверочные вопросы «Правда или ложь» и практические задачи, которые можно решить с помощью по-
20 | Предисловие лученных навыков программирования. Я настоятельно рекомендую решать эти за­ дания на протяжении всей книги. В дополнение к этому в книге рассматриваются 3 реальных проекта, на которых также можно поучиться программировать. Попро­ буйте воспроизвести эти проекты на собственном компьютере, и перед вами откро­ ется новый мир. Ближе к концу книги вы познакомитесь с анализом данных в Python. На наборах реальных данных мы будем изучать основы анализа. Наборы данных в виде файлов CSV можно скачать с моей учетной записи на GitHub, а в начале каждой главы бу­ дет указано точнее, откуда их можно скачать. Чтобы наиболее полно изучить биб­ лиотеки NumPy, Pandas и инструмент визуализации Matplotlib, советую вам скачать эти файлы с данными и попрактиковаться в использовании этих библиотек. Структура книги Книга разделена на 21 главу. Главы расположены так, что новые понятия програм­ мирования вводятся поочередно в порядке возрастания сложности. Так что даже для абсолютного новичка изучить новый материал будет так же легко, как и читать на родном языке. В главе 1 мы познакомимся с основами программирования, а также получим первое представление о невероятном мире анализа данных. Даже если у вас уже есть опыт работы с языками программирования, вам тем не менее стоит прочитать эту главу, т. к. сравнение Python с другими языками программирования может быть интерес­ но. Мы бегло познакомимся с такими сложными концепциями, как интерпретатор, компилятор и IDE. Вы также узнаете о работе специалистов по данным и аналити­ ков, а также о том, какие навыки необходимы для этой работы. В главе 2 мы начнем изучать язык программирования Python. Мы установим про­ граммное обеспечение Python с помощью дистрибутива Anaconda. Затем вы позна­ комитесь с приложениями IPython, Spyder IDE, Jupyter Notebook и впервые попро­ буете Python в действии. В главе 3 мы остановимся подробнее на интерфейсе Spyder IDE и Jupyter Notebook, вы узнаете как их использовать и запускать код Python, а также напишете первые простые примеры кода. В этой же главе мы начнем изучать синтаксис языка Python. Глава 4 рассказывает о переменных и объектах в Python. Затем мы рассмотрим иерархию типов, а также познакомимся с операторами Python. В главе 5 вы узнаете, как использовать условные операторы и циклы. Глава 6 посвящена функциям Python, и в ней вы узнаете, как вызывать встроенные функции, а также научитесь писать пользовательские функции. Вы также познако­ митесь с генераторами. Глава 7 — это первый проект, который позволит вам закрепить новые навыки. Вы научитесь создавать символьные рисунки с помощью циклов, а затем напишете функцию для выполнения повторяющейся работы.
Предисловие | 21 Глава 8 посвящена структурам данных в Python. Мы изучим строки, списки, корте­ жи, множества и словари. Кроме того, мы рассмотрим методы перебора всех этих типов в цикле. В главе 9 рассказывается, как можно прочитать в Python текстовый файл, порабо­ тать с ним и сохранить его в файл. Попутно рассмотрены методы ввода и вывода в Python. Глава 10— ваш второй проект. По ходу выполнения проекта вы познакомитесь с библиотекой обработки изображений Pillow. Этот проект посвящен автоматиза­ ции повторяющихся рутинных задач с помощью Python, чтобы сэкономить ваше время и энергию. В главе 11 вы подробно познакомитесь с понятием класса и с объектно-ориенти­ рованным программированием. Глава 12 рассказывает, с какими ошибками вы можете столкнуться и как их устра­ нять. Также вы узнаете, как обрабатывать ошибки с помощью исключений. В главе 13 мы подробно поговорим о модулях и пакетах в Python. Вы узнаете, как создавать свои собственные модули, как заставить их работать и как использовать общедоступные библиотеки. Глава 14 — ваш третий проект. Здесь мы изучим библиотеку Tkinter, с помощью которой можно создавать приложения с графическим интерфейсом пользователя для решения реальных задач. Вы также научитесь использовать методы API для загрузки данных с веб-сайтов. В главах 15 и 16 рассказывается о NumPy. Вы познакомитесь с этой очень популяр­ ной библиотекой Python и узнаете, как использовать ее тип данных ndarray для обработки абсолютно любых данных— от электронных таблиц до аудиофайлов и изображений. В главах 17 и 18 вы узнаете, как импортировать данные с помощью библиотеки Pandas и преобразовать их в объекты DataFrame. Затем вы научитесь различным опе­ рациям с данными, хранящимися в таких объектах. В главе 19 мы рассмотрим различные инструменты и способы визуализации в Python, включая простую, но мощную визуализацию с использованием Pandas. В главах 20 и 21 ваши навыки визуализации выйдут на новый уровень. Вы узнаете все о библиотеке Matplotlib и ее возможностях в визуализации данных. Мы рас­ смотрим примеры кода и графиков, которые пригодятся вам для решения любой задачи.
Об авторе Нилаб, каким я его знаю, полон энтузиазма, жизненной силы и огромного желания реализоваться. С первых дней знакомства я понял, что у него есть все задатки пре­ восходного учителя и наставника. Еще в те времена, когда мы были простыми про­ граммистами, по пальцам можно было сосчитать людей, с которыми я участвовал в технических дискуссиях, и Нилаб был в самом верху этого списка! За более чем 15 лет знакомства с ним я всегда восхищался уникальным набором сочетающихся в нем качеств— это и склонность углубляться в тему, терпение в выслушивании противоположной точки зрения, и в то же время острый ум, нацеленный на практи­ ческие задачи. Сегодня, когда я пишу это предисловие к его книге по Python, я от­ мечаю в его труде все те же достоинства: немалая строгость, подлинная простота, и твердая нацеленность на пользу читателю. Не секрет, что сегодняшний мир переживает невероятно быструю трансформацию, которая во многом происходит благодаря технологиям. В самом центре технологи­ ческих прорывов находятся развивающиеся области машинного обучения и искус­ ственного интеллекта. По-настоящему ценной эта книга по Python является потому, что этот труд представляет собой дорожную карту по изучению программирования для тех, кто уже что-то знает, и для тех, кто приступает к этой теме впервые. Зна­ ние Python позволит каждому принять участие в сегодняшней революции машин­ ного обучения. Я помню свои первые дни в качестве новичка-программиста на Python, и то, с ка­ ким трудом я осваивал некоторые концепции структур данных, даже выполняя простые операции в NumPy. Проблема с большей частью литературы по Python за­ ключается в том, что информация в книгах разрозненна и не учитывает отсутствие опыта у читателя. Нилаб в этой книге проложил для начинающих простой путь, который позволит им в будущем стать настоящими профессионалами. Само назва­ ние «Пошаговое руководство...» снимает опасения новичков, не имеющих опыта работы с программным обеспечением. Поток информации, изложенный в этой книге, выглядит актуально и прагматично. Показательный пример: книга начинается с установки необходимого программного обеспечения и его использования, а именно этот момент часто бывает затрудни­ тельным для новичков. В целом установить Python можно разными способами, но использование дистрибутива Anaconda, который предлагается в книге, — это, веро­ ятно, самый эффективный путь для начинающих. Для опытного программиста в этой книге найдутся интересные подробности, а также практические примеры и выводы. Например, объекты и операции в Python, за
24 | Об авторе которыми следуют операторы управления потоком, позволяют вам прочно закре­ пить свое понимание основ Python. Некоторые разделы этой книги заслуживают особого внимания, например функции, классы, структуры данных, а также создание модулей и пакетов. Существуют сотни библиотек Python, и любой уважающий себя специалист по Python должен уметь ими пользоваться. Даже парочка библиотек вроде NumPy и Pandas может сэкономить месяцы, если не годы, тяжелой работы для опытного программиста. И приятно видеть, что в этой книге Нилаб подробно говорит о NumPy и Pandas. Важный аспект анализа данных, который в большинстве книг по Python недоста­ точно хорошо освещен, — это визуализация. Но Нилаб подробно рассказал об этом, не забыв упомянуть различные библиотеки для визуализации и Matplotlib. Твердое понимание вопросов визуализации может помочь программисту вырасти от рядового сотрудника до руководителя. Опыт, который можно получить, как следует попрактиковавшись с кодом, не идет ни в какое сравнение с одним лишь теоретическим пониманием предмета. Эта кни­ га исповедует активный подход к обучению и вдохновляет читателя исследовать и экспериментировать, а не просто впитывать теорию. Это согласуется с моим собст­ венным убеждением, что лучший способ научиться программировать — это прак­ тика. Если бы годы назад ко мне в руки попала эта книга, я бы сэкономил месяцы, потра­ ченные на множество блогов, книг и сайтов, откуда черпал знания и идеи. Сегодня очень нужны профессионалы, готовые сразу же приступить к решению бизнесзадач. Больше не существует роскоши в виде длительной и непродуктивной учебы, выполняемой за счет вашего работодателя. Надеемся, что эта книга поможет вам восполнить этот пробел. На каждом этапе своей предпринимательской деятельности я всегда сталкивался с одной дилеммой выбора: создавать масштабируемый технологический продукт в ожидании будущего роста бизнеса или уделять силы и внимание текущему выжи­ ванию. Знания Python не только позволили мне быстро разработать нашу платфор­ му EduTech в компании Cobodh, но также помогли набраться знаний для принятия решений о будущем развитии. Даже сегодня, когда я стал уже бизнес-руководителем в индустрии облачных вычислений, мой опыт программирования помогает мне управлять командами, устанавливать правильные ожидания, а также отвечать на серьезнейшие вопросы во время встреч с клиентами из списка Fortune 500. Если вы хотите заслужить уважение в современную эпоху революционных технологий, самый лучший рецепт — научиться программировать! Подводя итог, отмечу, что мне эта книга видится полноценным продуктом для тех, кто начинает свой путь в программировании на языке Python. Надеюсь, она откроет вам дорогу к огромным знаниям программирования и множеству возможностей карьерного роста. Прилежному читателю и практику, помимо обширных знаний
Об авторе | 25 о Python, эта книга позволит развить бесценную привычку к постоянному исследо­ ванию и тестированию своего кода, что служит отличительной чертой хорошего специалиста по данным. Всем читателям желаю приятного приключения в программировании, которое, как я надеюсь, когда-нибудь позволит применить ваши навыки в Python на благо человечества! Анкит Куш, основатель и генеральный директор компании Cobodh, руководитель, регион АРАС, облачная маркетинговая аналитика, Searce (технарь и энтузиаст, грезящий о технологической сингулярности)
Благодарности Я невероятно рад, что вы относитесь к категории людей, которые читают раздел «Благодарности». В этом, дорогой читатель, мы похожи. А еще нам обоим интерес­ на тема этой книги. Процесс написания книги сродни воспитанию ребенка. На это требуется немало времени, труда, а самое главное — терпения. Причем терпение нужно не только тому парню, чье имя указано на обложке. Поскольку это моя первая книга, я чувст­ вовал себя словно неопытный родитель, которому требовалась помощь, советы и понимание. Все упомянутые далее люди очень помогли мне, и порядок, в кото­ ром я их благодарю, значения не имеет и совершенно случаен. Спасибо Прайти и Сунаяне за то, что уделяли мне время, место и частичку своей жизни, чтобы я мог осуществить свою мечту. Вы шли со мной рука об руку на про­ тяжении всего пути. Вы вложили в эту книге не меньше терпения и любви, чем я сам, а местами даже больше, потому что вам приходилось еще успокаивать меня, когда я был собой недоволен. Благодарю за то, что всегда были рядом и разделили со мной это путешествие. Спасибо Эшу, Ганешу Надару, Сваминату Госвами, Джейдипу Потдару, Мехгражу Пунджаби, Акшай Гехи, Пранаву Мишра и некоторым другим моим друзьям, кото­ рые попросили не упоминать их имена, за чтение первых черновиков и обратную связь. Невероятное количество черновиков так и осталось в столе, уступив место новым, лучшим вариантам, родившимся благодаря вам. Спасибо моему наставнику Судипто Макхержи за его неизбывную поддержку, по­ мощь со всеми необходимыми связями и мотивацию к получению новых знаний. Ваша всесторонняя помощь и советы сделали это путешествие еще более плодо­ творным. Спасибо моему дорогому другу Анкиту Кушу за то, что он взял на себя непосиль­ ную задачу прочитать всю книгу и написать к ней предисловие. Это просто неверо­ ятно, дружище. Спасибо человеку, который ввел в меня в мир писательства, — Радхике Матур. Я благодарен Вам за полный контроль над процессом и соблюдением сроков во всех моих делах. Без Вас этот проект так и не обрел бы ту форму, в которой он существует сейчас. Спасибо всем членам моей команды и коллегам, которые с ничуть не меньшим рвением поддерживали мой энтузиазм и время от времени давали ценные подсказ­ ки. Сандип, Ашутош, Паллави, Бирен, Анимеш, Харшал, Свапнил, Пранай, Анкит и
28 | Благодарности многие другие, чьи имена здесь не упомянуты (простите меня, если я кого-то за­ был) — знайте, что ваше мнение для меня невероятно ценно! Особая благодарность Вайшнави, который заставил меня в последний момент внести некоторые улучше­ ния и всегда давал слишком честную и прямолинейную обратную связь. Спасибо команде Notion Press, в которой работают настоящие профессионалы, в трудах своих выходящие за пределы необходимого. Особого упоминания заслу­ живает Саймон и Киртана Кумар, которые, незримо для остальных, занимались всеми вопросами дизайна и верстки. Особая благодарность моему менеджеру по публикации Хеме Приядаршини за выполнение бесконечного потока моих просьб и решение всех проблем, которые я время от времени создавал. Спасибо вам за то, что настолько облегчили весь этот путь, что я даже набрался смелости написать еще одну книгу, а после нее — множество других.
1 Введение в Data Science и основы программирования 1.1. Введение в Data Science Философы и мудрецы со всех концов света с незапамятных времен спорили о том, что будет править миром. Духовное или материальное? А вот информацию или данные никто в расчет не брал. Данные произвели революцию в технологиях в неменьшей степени, чем электриче­ ство. Сегодня происходит цифровая революция, которая чем-то похожа на самоисполняющееся пророчество. Она словно двигатель, который питает сам себя. Не пугайтесь. Как и во всех науках, в Data Science есть потенциал как для добра, так и для зла. Сама наука о данных отнюдь не нова, но именно появление компью­ теров и огромных возможностей обработки данных дало ей необходимый импульс. Сегодня данные буквально правят миром. Данные — это не король, а серый карди­ нал, который скрыто управляет всеми аспектами жизни. Подобное утверждение может показаться слишком надуманным или натянутым, но нет — это наша реаль­ ность, здесь и сейчас. Когда Amazon и Aliexpress на своих торговых площадках показывают вам товары, которые могут вас заинтересовать, именно данные лежат в основе этих предло­ жений. Когда политики во всем мире задействуют социальные сети и используют собран­ ные данные для социального профилирования, данные лежат в основе принятия важных решений, например о том, какой кандидат, где и как сможет выиграть вы­ боры. Когда Google Maps сообщает вам, насколько сильные пробки на дороге, приложе­ ние использует данные, собираемые в реальном времени, для перестроения мар­ шрута за вас. Когда аналитики рынка акций прогнозируют будущие котировки на фондовом рынке, они используют анализ данных. Сейчас сфера анализа данных и все связанные с ней области становятся прибыль­ нее с каждым днем. По мере того как все аспекты нашей жизни становятся все бо­ лее цифровыми, мы начинаем производить в секунду больше данных, чем наши
30 | Гпава 1 родители сумели создать за всю свою жизнь. Эти данные используются для приня­ тия важных решений как в режиме реального времени, так и с учетом анализа про­ шлых периодов. Проще говоря, Data Science — это наука об изучении данных для того, чтобы дан­ ные обрели смысл и дали нам полезную информацию. Эта наука не касается какойто конкретной предметной области, а являет собой сочетание различных дисцип­ лин, связанных с анализом данных и выдаче «умных» результатов и решений, основанных на этих данных. Data Science — это научная дисциплина, которая включает в себя извлечение ин­ формации из огромных объемов данных с использованием различных научных методов, алгоритмов и процессов. Эта наука помогает обнаруживать в необрабо­ танных данных скрытые закономерности. Data Science — это междисциплинарная область, которая помогает нам извлекать знания из структурированных или неструктурированных данных (рис. 1.1). Математика, статистика и алгоритмы лист по Data Science Программная инженерия Сбор данных Рис. 1.1. Взаимосвязь между компонентами Data Science 1.1.1. Зачем нам Data Science? Data Science как наука, занимающаяся изучением данных, помогает лучше прини­ мать решения, обнаруживать закономерности, составлять прогнозы, выполнять анализ и создавать визуальное представление из необработанных данных. Эта нау­ ка помогает нам: ♦ задавать правильные вопросы; ♦ находить основную причину проблемы; ♦ находить закономерности среди, на первый взгляд, хаотичных необработанных данных; ♦ создавать модели для предиктивного анализа;
Введение в Data Science и основы программирования | 31 ♦ визуализировать и отображать результаты с помощью графиков, информацион­ ных панелей и т. д.; ♦ наделять машины интеллектом; ♦ определять лояльность клиентов с помощью анализа настроений; ♦ принимать более качественные и быстрые решения; ♦ рекомендовать правильный продукт нужному клиенту для развития нашего биз­ неса. 1.1.2. История Data Science Data Science в ее нынешнем воплощении словно старое вино под новым брендом. А точнее — старый Джинн в новой бутылке. Сбор данных и составление на их основе значимых выводов — далеко не новое за­ нятие. Если подумать о сути этого процесса, станет ясно, что сбор данных выпол­ няется с доисторических времен. Например, цифры, используемые в древности пастухами, которым нужно было пересчитать свой скот, — это и были первые на­ боры данных. Форма данных могла отличаться, равно как и их масштаб, но на ос­ нове этих данных принимались жизненно важные решения. Животное Количество Овцы 23 Коровы 11 Козы 31 1.1.2.1. Данные в древности' Около 18 000 г. до н. э. Самый ранний способ хранения и анализа данных человеком датируется 18 000 г. до н. э. Кость Ишанго, обнаруженная в 1960 г. на территории современной Уганды, считается одним из самых ранних доисторических свидетельств хранения данных. Палеолитические племена делали зарубки на палках или костях, чтобы вести тор­ говую деятельность или подсчитывать припасы. Они сравнивали палки и насечки, выполняя тем самым элементарные расчеты, что позволяло предугадывать, напри­ мер, на сколько хватит их запасов еды. Около 2400 г. до н. э. Счеты — первое устройство, сконструированное специально для выполнения вы­ числений, впервые стали использоваться в Вавилоне. Примерно в это же время появились первые библиотеки — ранние попытки массового хранения данных. ' Marr, 2015 (https://www.linkedin.com/pulse/brief-history-big-data-everyone-should-read-bemard-marr/) [12].
32 | Гпава 1 1.1.2.2. Появление статистики' 1663 год В Лондоне ученый Джон Граунт проводит первый зарегистрированный экспери­ мент по статистическому анализу данных. Он предположил, что с помощью имею­ щихся данных о смертности ему удастся разработать систему раннего предупреж­ дения о бубонной чуме, опустошающей Европу. 1865 год Ричард Миллар Девенс в своей «Энциклопедии коммерческих и деловых анекдо­ тов» вводит термин бизнес-аналитика, описывая им то, как банкир Генри Фернезе добился преимущества перед конкурентами, собирая, анализируя и структурируя информацию, связанную с его коммерческой деятельностью. Этот труд считается первым исследованием, в котором анализ данных стал использоваться бизнесом в коммерческих целях. 1880 год У Бюро переписи населения США возникла проблема: по его оценкам, на обработку всех данных, собранных в ходе переписи 1880 г., потребуется 8 лет, а также было спрогнозировано, что обработка данных переписи 1890 г. займет более 10 лет, т. е. эти данные даже не успеют обработать до следующей переписи 1900 г. В 1881 г. молодой инженер по имени Герман Холлерит, нанятый Бюро, создает нечто, что позже будут называть Табулирующей машиной Холлерита. С помощью перфокарт он сократил 10 лет обработки данных до трех месяцев и занял свое место в истории как отец-основатель современных автоматизированных вычислений. Основанная им компания впоследствии станет называться IBM. 1.1.2.3. Зарождение современного хранения данных 1926 год В интервью журналу Colliers изобретатель Никола Тесла заявляет, что при пра­ вильном применении беспроводных технологий «всю планету можно превратить в огромный мозг, которым она, собственно, и является, ибо всё на ней является частицами настоящего и ритмичного целого... а приборы, с помощью которых это можно будет сделать, будут удивительно просты по сравнению с нашими нынеш­ ними телефонами. Этот прибор будет умещаться в кармане жилета». 1928 год Фриц Пфлеумер, немецко-австрийский инженер, изобретает метод магнитного хра­ нения информации на ленте. Принципы, которые он разработал, используются до сих пор, и почти все цифровые данные хранятся на жестких магнитных дисках компьютеров. 1 Marr, 2015 (https://www.linkedin.com/pulse/brief-history-big-data-everyone-should-read-bemard-marr/ ) [12]
Введение в Data Science и основы программирования | 33 1.1.2.4. Появление больших центров обработки данных 1965 год Правительство США планирует создать первый в мире центр обработки данных, в котором будут храниться 742 миллиона налоговых деклараций и 175 миллионов комплектов отпечатков пальцев на магнитной ленте. 1.1.2.5. Появление Интернета 1991 год Ученый-компьютерщик Тим Бернерс-Ли объявил о рождении того, что позже ста­ нет называться Интернетом, каким мы знаем его сегодня. 1997 год Появился сервис Google Search, и в течение следующих 20 лет название сервиса стало нарицательным, означающим поиск данных в Интернете. В том же году запускается журнал «Data Mining and Knowledge Discovery», причем такой порядок этих двух терминов в его названии отражает то, что термин Data Mining (сбор данных) стал более популярен, чем Knowledge Discovery (извлечение информации из больших баз данных). 2000 год 16 октября 2000 г. был выпущен язык Python 2.0 с множеством новых функций, включая сборщик мусора с обнаружением циклических ссылок и поддержку Unicode. 2010 год Эрик Шмидт, главный исполнительный директор Google, отметил на конференции, что сегодня каждые 2 дня создается столько же данных, сколько было создано че­ ловечеством с начала цивилизации до 2003 г. 2011 год В отчете McKinsey говорится, что к 2018 г. США столкнется с нехваткой от 140 000 до 190 000 профессиональных специалистов по обработке данных, а такие пробле­ мы, как конфиденциальность, безопасность и интеллектуальная собственность, должны быть решены до того, как большие данные раскроют весь свой потенциал. 2012 год В сентябре 2012 г. Том Дэвенпорт и Д. Дж. Патил публикуют статью «Data Scientist: The Sexiest Job of the 21st Century» («Специалист по обработке данных: самая сексуальная работа XXI века») в журнале Harvard Business Review. 2014 год Наблюдается рост мобильных устройств — для доступа к цифровым данным мо­ бильные устройства используются чаще, чем офисные и домашние компьютеры.
34 | Гпава 1 88 % руководителей предприятий, опрошенных GE совместно с Accenture, считают, что аналитика больших данных является основным приоритетом для их бизнеса. 1.1.3. Настоящее и будущее Data Science Сегодня развитие Data Science не закончилось и идет по нескольким направлениям (рис. 1.2). ♦ Искусственный интеллект (ИИ) — это сфера, в которой основное внимание уде­ ляется созданию интеллектуальных машин, способных работать и принимать решения как человек. Исследования в области ИИ начались около 1936 г., когда Алан Тьюринг создал первые машины на базе ИИ. Несмотря на довольно дол­ гую историю, сегодняшний ИИ в большинстве областей все еще не способен полностью заменить человека. Соревнование ИИ с людьми в шахматах и шиф­ рование данных — это две стороны одной медали. Рис. 1.2. Связь между искусственным интеллектом, машинным обучением, глубоким обучением и Data Science ♦ Машинное обучение— это инструмент для извлечения знаний из данных. В машинном обучении модели могут обучаться на данных самостоятельно или поэтапно: обучение с учителем, т. е. на данных, подготовленных человеком, или обучение без учителя, в котором работа ведется над хаотичными и неорганизо­ ванными данными. ♦ Глубокое обучение — это создание многослойных нейронных сетей в областях, где требуется более продвинутый или быстрый анализ, а традиционное машин­ ное обучение не справляется. Под глубиной понимается наличие более одного скрытого слоя нейронов в сети, которые проводят математические вычисления. ♦ Большие данные — это работа с огромными объемами часто неструктуриро­ ванных данных. Специфика этой сферы — инструменты и системы, способные выдерживать высокие нагрузки.
Введение в Data Science и основы программирования | 35 1.1.4. Чем занимается специалист по Data Science? «Специалист по Data Science — это человек, который разбирается в статистике лучше любого программиста и программирует лучше любого статистика» (Джош Уиллс). Специалист по Data Science анализирует бизнес-данные, извлекая из них важную информацию. Другими словами, специалист по анализу данных решает бизнесзадачи с помощью следующих шагов: ♦ задает правильные вопросы, чтобы понять проблему; ♦ собирает данные из нескольких источников — корпоративные данные, общедос­ тупные данные и т. д.; ♦ обрабатывает сырые данные и преобразует их в формат, подходящий для ана­ лиза; ♦ загружает данные в аналитическую систему — алгоритм машинного обучения или статистическая модель; ♦ подготавливает результаты и идеи, которые можно изложить заинтересованным сторонам. Всё это позволяет решить немало проблем, некоторые из них приведены далее: ♦ обнаружение мошенничества и выявление аномалий, например изменений схе­ мы снятия или расходования средств с кредитной карты клиента; ♦ целевой и персонализированный маркетинг— персональные рассылки по элек­ тронной почте, системы рекомендаций на сайтах магазинов; ♦ метрические прогнозы — показатели эффективности, качества рекламных кам­ паний и других мероприятий; ♦ оценка принятия решений — обработка больших объемов данных и помощь в принятии решения, например о выдаче кредита на основе кредитных оценок; ♦ прогнозирующее моделирование— прогнозирование столкновения метеорита с землей на основе астрономических данных. Это лишь малая часть тем, которыми занимается специалист по данным. 1.1.5. Как это делается? Ответ на этот вопрос мы шаг за шагом узнаем по мере изучения этой книги. А еще он показан на рис. 1.3. 1.1.6. Предпосылки для Data Science ♦ Программирование Для успешного выполнения проекта по Data Science требуются определенные навыки программирования. Наиболее распространенными языками программи­ рования являются Python и R. Язык Python особенно популярен, потому что он
36 | Гпава 1 1. Понимание бизнеса данных 7. Визуализация данных Data Science 6. Составление прогнозных х моделей 5. Выявление признаков 3. Очистка данных 4. Исследование данных Рис. 1.3. Последовательность шагов Data Science прост в изучении и поддерживает несколько библиотек для Data Science и ма­ шинного обучения. ♦ Статистика Статистика лежит в основе Data Science. Правильная обработка статистики может помочь вам извлечь больше информации и получить более значимые результаты. ♦ Базы данных Будучи специалистом по данным, вам необходимо понимать, как работают базы данных, как ими управлять и как извлекать из них данные. ♦ Моделирование Математические модели позволяют выполнять вычисления и прогнозы на осно­ ве того, что вы уже знаете о данных. Моделирование также относится к машин­ ному обучению и включает определение того, какой алгоритм больше подходит для решения данной проблемы и как обучать эти модели. 1.1.7. Профессии в области Data Science Наиболее известные профессии в Data Science следующие: ♦ специалист по данным; ♦ дата-инженер; ♦ аналитик данных; ♦ статистик; ♦ архитектор данных; ♦ администратор данных;
Введение в Data Science и основы программирования | 37 ♦ бизнес-аналитик; ♦ менеджер данных/аналитики. Давайте подробно узнаем, с чем связана каждая из этих профессий: ♦ Специалист по данным Роль: специалист по данным — это профессионал, который манипулирует огромными объемами данных для создания серьезных бизнес-концепций, ис­ пользуя различные инструменты, методы, методологии, алгоритмы и т. д. Языки: R, SAS, Python, SQL, Hive, MATLAB, Pig, Spark. ♦ Дата-инженер Роль: его роль заключается в работе с большими объемами данных. Он разраба­ тывает, конструирует, тестирует и поддерживает крупномасштабные системы обработки и базы данных. Языки: SQL, Hive, R, SAS, MATLAB, Python, Java, Ruby, C++ и Perl. ♦ Аналитик данных Роль: аналитик данных отвечает за сбор огромных объемов данных. Этот спе­ циалист будет искать в данных отношения, закономерности и тенденции. Позже он составляет убедительную отчетность и визуализацию для анализа данных, чтобы принять наиболее жизнеспособные бизнес-решения. Языки: R, Python, HTML, JS, С, C++, SQL. ♦ Статистик Роль: статистик собирает, анализирует и обрабатывает качественные и количе­ ственные данные, используя статистические теории и методы. Языки: SQL, R, MATLAB, Tableau, Python, Perl, Spark и Hive ♦ Администратор данных Роль: администратор данных должен обеспечить доступ к базе данных для всех пользователей. Он также следит за тем, чтобы программа работала правильно и была защищена от взлома. Языки: Ruby on Rails, SQL, Java, С # и Python. ♦ Бизнес-аналитик Роль: этот специалист занимается улучшением бизнес-процессов. Он является связующим звеном между руководством и 1Т-отделом. Языки: SQL, Tableau, Power BI и Python. Вы заметили, какой язык или языки используются во всех этих профессиях? 1.2. От Data Science к программированию В последнее время само словосочетание Data Science стало модным и проникло во все аспекты жизни и бизнеса. То, что начиналось как использование компьютеров для ускорения вычислений, на которые раньше тратились годы, а теперь выполня-
38 | Гпава 1 ются за минуты, в последнее десятилетие превратилось в совершенно другую исто­ рию. Data Science стала самостоятельным, важным и очень привлекательным на­ правлением. Итак, теперь у вас есть представление, что такое Data Science и с чем это едят. Но поверьте мне, на самом деле мы даже верхушку айсберга еще не видели. Горизонты здесь буквально безграничны. Существуют новейшие и очень интересные технологии, основанные на Data Science, — это автомобили с автоматическим управлением, персональные цифро­ вые помощники (Alexa, Google Assistant, Siri и т. д.), динамичные сервисы пробок и навигации на цифровых картах и, конечно же, персонализация опыта покупок. Для специалистов по данным настали интересные времена. Но знать о возмож­ ностях лишь теоретически — это не столь весело, не так ли? Итак, давайте закатаем рукава и узнаем, как писать программы, которые будут пре­ вращать данные в полезные знания. 1.3. Основы компьютерного программирования Открою вам секрет. Еще не так давно слово программирование меня пугало. Я ре­ шил разобраться с этим, и, как оказалось, бояться тут нечего. Единственная про­ блема, с которой я столкнулся, заключалась не в нехватке материалов для чтения (потому что на самом деле материалов так много, что ты буквально в них тонешь), а в том, с чего начать и какой путь правильный. И именно с этими вопросами я собираюсь вам помочь. Мы вместе отправимся в увлекательное путешествие и расширим ваши горизонты. Давайте узнаем, как научиться общаться с вашим компьютером, чем, по сути, и занимаются програм­ мисты. 1.3.1. Что такое программирование? Конечный результат компьютерного программирования нам всем известен. Когда мы играем в любимые игры на смартфоне или компьютере, открываем любое мобильное приложение или программу на компьютере, делаем фото, смотрим фо­ тографии на любом экране или даже отправляем электронную почту, программы постоянно работают в фоновом режиме, выполняя разную работу, которую мы во­ обще никогда не видим. Компьютер — это послушный, но не слишком умный слуга. Он делает в точности то, что мы ему говорим, ни больше ни меньше. Следовательно, когда мы даем ком­ пьютеру инструкции (посредством программ), эти инструкции должны быть кон­ кретными и последовательными. Самая подходящая аналогия, которую я могу придумать, — это кулинарный рецепт. Возьмем простой рецепт приготовления хлеба. В рецепте используется не-
Введение в Data Science и основы программирования | 39 сколько ингредиентов, таких как мука, вода и дрожжи (если мы говорим о выпеч­ ке). Каждый ингредиент добавляется в определенной пропорции. Если налить два стакана воды вместо одного, то тесто становится слишком жидким, чтобы держать форму. Точно так же работают инструкции, которые мы даем компьютеру: они должны быть конкретными, чтобы можно было получить желаемые результаты. Компьютеры весьма буквальны и стараются исполнять наши команды в точности. Если мы даем компьютеру неверные команды, они могут вообще не сработать. Или, что еще хуже, может возникнуть ошибка или сбой программы. Еще одна характеристика компьютерной программы заключается в том, что она последовательна, как шаги в рецепте. Последовательность шагов определяет ко­ нечный продукт. Что будет, если при приготовлении хлеба чапати мы сразу поста­ вим его на огонь, а не прогреем в течение некоторого времени на горячей плите? Хлеб сломается и потеряет форму. Или что будет, если сначала мы поставим в ду­ ховку муку, и уже потом добавим воду, чтобы замесить тесто? Из пропеченой муки тесто не получится. Порядок действий имеет значение. То же самое можно сказать и о программировании. Ваша задача состоит в том, чтобы дать компьютеру пра­ вильные инструкции и правильную последовательность шагов для получения желаемого результата. Итак, программирование — это то, как мы общаемся с компьютером. Программу определяют инструкции, которые являются конкретными и последовательными. И точно так же, как рецепт, когда программа составлена правильно, нас порадует конечный результат. Иными словами, программирование — это идеи, преобразованные в пошаговые инструкции, понятные компьютеру. Такая пошаговая инструкция называется алго­ ритмом. 1.3.2. Компьютерный алгоритм Чтобы заставить компьютер сделать что-либо, инструкции должны быть записаны в виде компьютерной программы. В компьютерной программе вы должны после­ довательно указать, что именно вы от него хотите. Затем компьютер запускает про­ грамму и выполняет ее шаг за шагом, чтобы сделать требуемую задачу. Когда вы говорите компьютеру, что делать, нужно также сообщить ему, как это делать. Так устроен компьютерный алгоритм. В информатике алгоритм — это конечная последовательность четко определен­ ных, реализуемых компьютером инструкций для решения какой-то проблемы или для выполнения вычислений. Алгоритмы всегда однозначны и используются для вычислений, обработки данных, автоматизированных решений и других задач. В компьютерных системах алгоритм — это пример логики, написанной разработ­ чиками программного обеспечения для эффективного выполнения на целевом ком­ пьютере и для получения некоторых выходных данных по заданным входным дан­ ным. Оптимальный алгоритм дает более быстрые результаты, чем неоптимальный алгоритм для решения той же задачи. Вот почему алгоритмы, как и компьютерное оборудование, считаются технологиями.
40 | Гпава 1 Приведу несколько примеров алгоритмов. Давайте сначала возьмем реальный слу­ чай, а затем рассмотрим вычислительный пример. Реальный пример алгоритма Напишем алгоритм приготовления чая. Ингредиенты: вода, сахар, молоко и чайные листья на две чашки чая. Шаг 1. Начало. Шаг 2: Возьмите ковшик и налейте в него один стакан воды. Шаг 3: Зажгите конфорку и поставьте на нее ковшик. Шаг 4: Доведите воду до кипения. Шаг 5: Добавьте в кипящую воду две столовые ложки сахара и две столовые ложки чайных листьев. Шаг 6: Добавьте в кипящую смесь одну чашку молока. Шаг 7: Варите содержимое в течение одной минуты. Шаг 8: Выключите конфорку. Шаг 9: Процедите чай через сито. Шаг 10: Разлейте чай по чашкам и подавайте. Шаг 11: Конец. Пример вычислительного алгоритма Напишите алгоритм того, как сложить 2 + 2 и получить 4 в качестве результата. Шаг 1: Шаг 2: Шаг 3: Шаг 4: Начало. Введите 2 + 2. Нажмите клавишу <Enter>. Конец. В целом алгоритмы состоят из 3 видов операторов, которые могут присутствовать в различных комбинациях: 1. Последовательные операторы. 2. Условные операторы. 3. Циклы или итерации. 1.3.2.1. Последовательные операторы Эти операторы выполняются один за другим, последовательно. Приведенные ранее примеры, как заваривание чая, так и вычисление 2 + 2, являют­ ся примерами последовательных операторов. Рассмотрим еще пару примеров. Пример. Как рассчитать возраст человека по году его рождения. Шаг 1: Начало. Шаг 2: Возьмите год рождения человека и сохраните это число как YOB. Шаг 3: Возьмите текущий год и сохраните его как СУ.
Введение в Data Science и основы программирования | 41 Шаг 4: Вычтите YOB из CY и сохраните как Аде. Шаг 5: Выведите значение Аде. Шаг 6: Конец. 1.3.2.2. Условные операторы В таких программах некоторая часть программы выполняется в зависимости от определенного условия. Если условие верное, компьютер выполняет одну часть программы, а если условие неверное, то выполняется другая часть программы. Пример. Напишите алгоритм, который проверяет, заболел ли человек. Считаем, что человек заболел, если температура его тела выше 37 °C. Шаг 1: Начало. Шаг 2: Измерьте температуру и сохраните ее в TEMP. Шаг 3: Проверьте значение TEMP. Если оно превышает 37 градусов, переходите к шагу 4, в противном случае переходите к шагу 5. Шаг 4: Выведите «Пациент болеет» и переходите к шагу 6. Шаг 5: Выведите «Пациент здоров». Шаг 6: Конец. 1.3.2.3. Цикл или итерации В некоторых программах определенный набор действий нужно выполнять снова и снова в зависимости от некоторого условия. Эти повторяющиеся действия называ­ ются итерациями. Итерация выполняется с использованием одного или нескольких операторов цикла, поэтому программы такого типа называются циклическими или повторяющимися. Пример. Вывести на экран все числа от 1 до 10. Шаг 1: Начало. Шаг 2: Сохраните значение 1 в /. Шаг 3: Проверьте, выполняется ли условие /2 10. Если да, то переходите к шагу 4. Если нет, переходите к шагу 7. Шаг 4: Выведите значение / на экран. Шаг 5: Увеличьте значение / на 1. Шаг 6: Переходите к шагу 3. Шаг 7: Конец. В этом примере шаги с 3-го по 5-й повторяются до тех пор, пока условие шага 3 выполняется. Как только условие станет неверным, цикл завершится. 1.3.3. Блок-схемы Алгоритмы можно изображать в графической форме с использованием определен­ ных обозначений. Полученное изображение называется блок-схемой.
42 | Гпава 1 В блок-схемах для представления различных функций программ используются некоторые стандартные символы. Эти символы представлены на рис. 1.4. Давайте рассмотрим пример блок-схемы. Пример. Напишите программу, которая проверяет, является число четным или не­ четным (рис. 1.5). Рис. 1.4. Обозначения, используемые в блок-схемах Рис. 1.5. Алгоритм определения четности числа Во введении в Data Science мы уже сказали кое-что о языках программирования. Давайте теперь разберемся, что это такое? Чем они похожи и чем отличаются от языков, на которых мы говорим и пишем? 1.3.4. Что такое язык программирования? Если мы хотим дать компьютеру какие-то указания, нужен язык программиро­ вания. Разных языков программирования существует очень много. Как и у раз­ говорных языков, у всех языков программирования есть свои правила (синтаксис) и значения (семантика). В жизни мы на разных языках используем разные слова, написание и произношение для обозначения одних и тех же вещей, и точно так же одно и то же сообщение на разных языках программирования пишется по-разному. Чтобы проиллюстрировать разницу между языками программирования, я покажу вам пример одной и той же программы, написанный на разных языках. Вы сами увидите различия.
Введение в Data Science и основы программирования | 43 Программа «Hello World!» на C++ #include <iostream> int main() { std::cout « "Hello World!"; return 0; } Программа «Hello World!» на Java class HelioWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } Программа «Hello World!» на Python print("Hello World!") Это простейшая из возможных программ на многих языках, которая обычно ис­ пользуется для демонстрации. Я не ожидаю от вас мгновенного понимания того, как программа пишется или выполняется, поскольку мы вернемся к этому вопросу позже. А пока давайте выделим различия в синтаксисе между языками. Во-первых, взглянем на язык программирования C++. В приведенном выше коде показано, как научить программу при запуске выводить на экран текст «Hello World!». Здесь я хочу обратить ваше внимание на синтаксис, используемый в язы­ ке. Он состоит из двойных кавычек вокруг текста "Hello World!", точки с запятой в конце операторов и ключевого слова return перед закрывающей фигурной скоб­ кой. Всё это является частью синтаксиса или правил языка программирования C++. Второй пример написан на языке программирования Java. На сегодняшний день это один из самых популярных языков, используемых в мобильных приложениях и программах в целом. Обратите внимание, как выглядит код вывода «Hello World!» на Java. Обратите внимание на отличия в синтаксисе. Теперь посмотрим на тот же «Hello World!» на языке программирования Python. Это один из самых популярных языков в сфере Data Science и машинном обучении. Обратите внимание, что здесь синтаксис совершенно другой — намного проще и лаконичнее. Вы, должно быть, думаете, зачем нам вообще такое количество языков и почему нельзя всем использовать только один язык программирования. Причина в том, что у всех языков программирования есть свои сильные и слабые стороны. Некоторые из них идеально подходят для создания веб-сайтов, другие — для мобильных при­ ложений, а третьи предназначены для выполнения сложных математических рас­ четов. Независимо от того, какой язык программирования вы выбрали, компьютер все равно его не понимает. Компьютер понимает совершенно другой язык, который
44 | Гпава 1 называется машинным языком. Но нам было бы сложно писать программы напря­ мую на машинном языке, потому что он очень сложен и состоит в основном из последовательностей чисел. Именно поэтому приведенные выше языки програм­ мирования называются языками высокого уровня, т. к. они более похожи на естест­ венные человеческие языки. 1.3.5. Что такое исходный код? Исходный код — это то, что пишут программисты на всех языках программирова­ ния. Это те самые указания, которые мы даем компьютеру, написанные неформа­ тированным текстом. В таком тесте нет таких средств форматирования, как выде­ ление полужирным, курсив или подчеркивание. Следовательно, текстовые процес­ соры, такие как MS Word, Libre Office или Google Docs, для написания исходного кода не годятся. Все дело в том, что текстовые процессоры, когда мы используем их для написания текста, добавляют в него дополнительную разметку, например, тип шрифта, отступы, полужирный/курсив и т. д. Исходный код должен быть про­ стым, без всякой разметки и форматирования. Вместо этого вы можете использовать текстовые редакторы. На всех персональ­ ных компьютерах с операционной системой Windows по умолчанию установлен редактор Notepad (Блокнот). У пользователей MacOS есть TextEdit. Существует также множество других текстовых редакторов. Просто помните, что форматиро­ ванный текст не подходит для исходного кода, подходит только неформатирован­ ный текст. Теперь вы можете написать свою первую компьютерную программу или исходный код. Мы напишем ту же программу, с которой принято начинать обучение. Тот самый пример «Hello World!». Будем использовать синтаксис языка Python. Итак, откройте Блокнот или любой другой текстовый редактор и напишите: print("Hello World!") Мои поздравления — вы написали свой первый исходный код. Исходный код может быть очень простым и состоять из одной строки, как мы толь­ ко что написали, а может состоять из тысяч сложных строк. Все зависит от потреб­ ностей и целей вашей программы. Теперь сохраним наш исходный код. У каждого языка программирования свой формат файла или расширение. По умолчанию текстовый редактор сохраняет фай­ лы в формате txt. Но мы сохраним его с расширением, подходящим для Python, т. к. мы написали исходный код для Python. Расширение файла Python— ру. Давайте сохраним файл под именем HeIlo_World.py. Теперь мы знаем, как писать исходный код, а также сохранять его. Пришло время научиться переводить его на машинный язык, который понимает компьютер.
Введение в Data Science и основы программирования | 45 1.3.6. Как запустить исходный код? Вы написали свой первый исходный код. Теперь его надо запустить. Давайте попробуем запустить его привычным образом — двойным щелчком по файлу. Что из этого вышло? Файл просто открывается как текстовый файл, а иногда у вас сначала спросят, какую программу использовать для открытия файла, и если вы выберете Блокнот, то ваш код снова откроется как текстовый файл. Неожиданный поворот. И даже разочаровывающий... Не так ли? В чем смысл исходного кода, который не запускается? Причина проста. Код написан не на том языке, который понимает компьютер, и мы не скомпилировали и не интерпретировали исходный код. Сейчас вы, наверное, запутались еще больше, потому что никогда не слышали таких слов. Давайте разбираться. Существуют три основных способа перевода исходного кода в машинный код: ♦ компиляция; ♦ интерпретация; ♦ сочетание этих двух способов. Компиляция и интерпретация исходного кода— это очень сложные процессы, и вдаваться в технические подробности того, как они устроены внутри, мы не будем. Вместо этого я постараюсь простым языком объяснить, что означают эти термины. Приведем аналогию. 1.3.7. Компилятор Компилятор — это программа, преобразующая исходный код в машинный. Рассмотрим пример. Вы пишете письмо своему другу на английском языке, а он понимает только хинди. Тогда вы пишете письмо на английском и используете программу-нфеводчмк, чтобы перевести английский текст на хинди (рис. 1.6). Ана- Рис. 1.6. Перевод с английского на хинди
46 | Гпава 1 func greet О « < Console.printlnpHello, World!") 10100111100 11110011001 10010010010 10110111001 11101111011 Исходный код на языке программирования Машинный язык Рис. 1.7. Компиляция с языка программирования высокого уровня на машинный язык логичным образом компилятор переводит или, скорее, компилирует исходный код с языка программирования высокого уровня на машинный язык (рис. 1.7). Приведенное изображение является чрезмерным упрощением очень сложного про­ цесса компиляции, в который мы специально не углубляемся. Цель нашей книги состоит не в этом. Если вам интересно, вы можете поискать информацию о компи­ ляторах в Интернете, и там вы найдете достаточно материала, чтобы утолить жаж­ ду знаний. 1.3.8. Интерпретатор В компьютерном программировании интерпретатор — это компьютерная про­ грамма, которая непосредственно выполняет инструкции, написанные на языке программирования, без предварительной компиляции в программу на машинном языке. Продолжим предыдущую аналогию: вы написали письмо своему другу на англий­ ском, который понимает только хинди. Вместо того, чтобы переводить письмо на хинди, вы отправляете ему английский текст. А он, получив письмо, вызывает переводчика, который должен будет прийти и расшифровать значение письма, строка за строкой. Каждый раз, когда ему захочется прочитать письмо еще раз, ему нужно будет снова вызывать переводчика. Именно этим и занимаются компьютерные интерпретаторы: они построчно обраба­ тывают исходный код при каждом запуске, а у пользователя на компьютере должен быть установлен необходимый интерпретатор. Некоторые языки программирования относятся к компилируемым, например С, C++ и Objective С. Другие языки программирования являются интерпретируемыми, например PHP, JavaScript и т. д. Также существуют языки программирования, в которых используется комбинация обоих методов, например Python, Java, С#.
Введение в Data Science и основы программирования | 47 1.3.8.1. Сравнение компилятора и интерпретатора Основные различия между компиляторами и интерпретаторами: 1. И компиляторы, и интерпретаторы преобразуют исходный код (текстовые фай­ лы) в машинный язык. Основное их отличие состоит в том, что компилятор генерирует автономную программу, написанную на машинном коде, а система интерпретатора выполняет действия, описанные программой высокого уровня. 2. После компиляции программы ее исходный код для запуска больше не требует­ ся. У интерпретируемых программ исходный код требуется для запуска про­ граммы каждый раз. 3. Обычно интерпретируемые программы работают медленнее, чем компили­ руемые. Получается, что для запуска кода на компьютере потребуется приложить дополни­ тельные усилия, кроме написания исходного кода. Поскольку мы используем язык Python, то думать о том, как использовать компи­ лятор или интерпретатор, нам не нужно. Когда мы устанавливаем Python на свой компьютер (или любое программное обеспечение, связанное с языком программи­ рования), интерпретатор идет в комплекте. После установки Python творит магию сам, и нам не нужно беспокоиться об этом. 1.3.9. Что такое интегрированная среда разработки (IDE)? Писать все программы можно так же, как вы написали свой первый исходный код, т. е. в простом текстовом редакторе. Но это не самый эффективный или элегантный метод работы. Для решения специфичных задач всегда существует специальное программное обеспечение. Например, когда нужно работать с данными, таблицами и расчетами, мы используем программы для работы с электронными таблицами (например, Microsoft Excel), а если нужна презентация, используем PowerPoint. Для создания или открытия текстовых документов используются текстовые редакторы. Нетрудно предположить, что для написания компьютерных программ существуют интегри­ рованные среды разработки или IDE (Integrated Development Environment). В этих программах есть специальные инструменты, необходимые для написания, отладки и компиляции кода. Поскольку мы изучаем Python, мы будем использовать IDE, поддерживающие язык Python. Дефицита IDE для Python не наблюдается — можно использовать любую. Но я рекомендую начать со стандартного программного обеспечения, т. к. оно проще в установке и использовании. Скорее всего, вы так и будете использовать эти программы дальше, поскольку они весьма эффективны. Мы будем использовать Spyder ГОЕ. Загрузку и установку выполним чуть позже, а пока познакомимся со средой, чтобы вы оценили эффективность и удобство, кото­ рую IDE привносит в написание кода (или в программирование).
48 | Гпава 1 1.3.10. Spyder IDE Spyder IDE (Scientific Python Development Environment) — это бесплатная научная среда разработки на Python, которая входит в состав дистрибутива Anaconda (па­ кетное программное обеспечение для Python— мы узнаем об этом в следующей главе). В этой IDE есть функции редактирования, проверки, отладки и интерактив­ ного тестирования. О том, как использовать Spyder, мы подробно поговорим в следующих главах, а пока рассмотрим, чем IDE лучше обычного текстового редактора. На рис. 1.8 показан общий вид среды Spyder IDE. Область в середине, выделенная черной рамкой, — это панель редактора. Это эквивалент окна текстового редак­ тора, в котором мы пишем текст программы (неформатированный, как мы уже знаем). Рис. 1.8. Spyder IDE для Python Первое, что бросается в глаза, — это разница между простым текстовым редакто­ ром и более сложной IDE. В левой части редактора исходного кода есть номера строк. Это позволяет нам быстрее находить отдельные команды кода. Также в IDE используется выделение синтаксиса цветом, что помогает видеть в коде ключевые слова и улучшает читаемость кода. Наконец, обратите внимание, что в IDE есть возможность предварительно просмотреть, как будет выглядеть ваш код при ком­ пиляции и запуске на реальном устройстве. Определенно, это отличный инстру­ мент для улучшения процесса кодирования.
Введение в Data Science и основы программирования | 49 1.4. Резюме Мы немного познакомились с захватывающим миром Data Science и узнали, что, хотя новые времена и технологии изменили правила игры, наши предки уже знали важность анализа данных. Статистика — это основа принятия всех решений, свя­ занных с данными. Огромная вычислительная мощность компьютеров сделала воз­ можным решение задач, которые еще несколько десятилетий назад рассматрива­ лись лишь в теории. Мы также узнали, какой работой занимается специалист по данным, чем она похо­ жа и чем отличается от работы аналитика данных, дата-инженера и других специа­ листов, работающих с данными. Мы также отметили, что Python — это единствен­ ный язык, который часто используется во всех областях, связанных с Data Science. Мы также познакомились с компьютерным программированием. И даже написали первый исходный код. В следующей главе мы узнаем больше о языке Python, а также загрузим и устано­ вим программное обеспечение и пакеты Python, в том числе и Spyder IDE. По ходу дела мы разберемся с разными функциями IDE и Python. 1.5. Упражнения 1.5.1. Ответьте на вопросы I. Какие предметные области входят в Data Science? Что между ними общего и в чем различие? 2. Как вы понимаете термин «алгоритм»? Как алгоритмы связаны с блок-схемами? 3. Какую программу можно назвать хорошей? Запишите все характеристики, какие удастся придумать. 4. Какой язык понимает компьютер? 5. Чем языки программирования отличаются от языков, на которых мы говорим? 1.5.2. Правда или ложь 1. Машинное обучение — это инструмент для извлечения знаний из данных. 2. Глубокое обучение — это то же самое, что машинное обучение. 3. Все инженеры-программисты также могут считаться специалистами по данным. 4. Статистика — важный инструмент для специалистов по данным. 5. Компьютер может принимать решения, выходящие за рамки данных ему инст­ рукций, подстраиваясь под изменения среды. 6. Компьютеры понимают языки программирования «как есть». 7. Некоторые языки программирования компилируются, некоторые интерпрети­ руются, а некоторые используют и то и другое.
50 | Гпава 1 8. Все программы выполняются последовательно. 9. В IDE есть встроенный текстовый редактор. 10. Компиляторы и интерпретаторы— это такие механизмы, наподобие привода для компакт-дисков. 1.5.3. Практические задания 1. Напишите алгоритм для расчета простых процентов от некоторой суммы. 2. Напишите алгоритм для вычисления площади прямоугольника. 3. Напишите алгоритм вычисления периметра круга. 4. Напишите алгоритм, который находит все простые числа меньше 100. 5. Напишите алгоритм превращения предложения, написанного в верхнем регист­ ре, в обычный для предложений регистр. 6. Составьте блок-схему приготовления льда из кипяченой воды с помощью холо­ дильника. 7. Составьте блок-схему для нахождения суммы всех четных чисел меньше ста. 8. Составьте блок-схему для вычисления квадрата всех нечетных чисел от 1 до 15 включительно. 9. Составьте блок-схему вывода таблицы умножения на 3. 10. Составьте блок-схему для расчета сложных процентов (с капитализацией). 1.5.4. Изучите самостоятельно 1. Что думают ученые о будущем Data Science? Изучите материалы на эту тему и поделитесь ими с друзьями. 2. Составьте список разных IDE для языка Python. Узнайте, чем они похожи и чем отличаются. 3. Составьте список всех компилируемых и интерпретируемых языков. Найдите ситуации, в которых каждый из них будет полезнее в использовании, чем остальные. 4. Создайте алгоритмы для решения некоторых распространенных задач, с кото­ рыми вы сталкиваетесь в повседневной жизни. Составьте для них блок-схемы. 5. Как вы думаете, может ли изучение компьютерного программирования помочь автоматизировать какие-нибудь повторяющиеся рутинные задачи? Подготовьте список таких задач и попробуйте автоматизировать их по мере изучения этой книги.
2 Введение в Python 2.1. Что такое Python? Python — это бесплатный интерпретируемый высокоуровневый язык программи­ рования общего назначения с открытым исходным кодом. Python был создан Гвидо ван Россумом и впервые выпущен в 1991 г. Он поддержи­ вает несколько парадигм программирования, включая структурное (особенно про­ цедурное) объектно-ориентированное и функциональное программирование. Его языковые конструкции и объектно-ориентированный подход позволяют програм­ мистам писать понятный и логичный код в рамках как небольших, так и крупно­ масштабных проектов1. Python — это простой в освоении и очень мощный язык программирования (рис. 2.1). Элегантный синтаксис и динамическая типизация Python вместе с его интерпретируемостью делают его идеальным языком для написания сценариев и быстрой разработки приложений во многих областях и на множестве платформ2. Iя python Бесплатный и открытый код Интерпрети­ руемый язык Высокоуровневость и общее назначение Портативность и простота изучения Язык программирования Рис. 2.1. Что такое Python 2.1.1. Почему именно Python? Когда я среди сотен языков программирования выбирал язык для изучения, у меня был простой критерий. Язык должен быть простым в изучении и использовании, а также популярным среди программистов. 1 Wikipedia, 2020 (https://en.wikipedia.org/w/index.php?title-History of_ Python) [50]. 2 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
52 | Гпава 2 Что касается популярности, то самыми популярными языками программирования для специалистов по данным являются: ♦ Python ♦ С++ ♦ R ♦ Java ♦ SQL ♦ Matlab Если выначинаете карьеру программиста или хотите выучить свой первый язык программирования, то будет разумно остановиться на одном из самых популярных и признанных языков программирования. Следовательно, язык, который мы изуча­ ем, должен удовлетворять всем следующим критериям: ♦ Это один из самых популярных языков программирования, прочно вошедший в индустрию разработки программного обеспечения. ♦ Занимает первое место среди языков-аналогов согласно рейтингам из открытых источников или статей по языкам программирования. ♦ Стабильно популярный, а еще лучше с растущей популярностью. ♦ У языка есть большой набор библиотек, инструменты, фреймворки и большое сообщество, которое вносит свой вклад в развитие языка. ♦ Язык хорошо востребован на рынке труда и позволяет получать хорошую зар­ плату. Среди перечисленных выше популярных языков единственный язык, который со­ ответствует всем этим критериям, а также самый простой для изучения и использо­ вания — это Python. Кроме того, Python гибок в настройке и может быть расширен на другие платформы. В автономном виде это довольно мощный язык для решения множества задач. У Python открытый исходный код, и он широко используется. Модули и библиотеки находятся в свободном доступе, и их число растет с каждым днем. Python также очень хорошо приспособлен для решения задач интеллектуального анализа данных, аналитики данных и машинного обучения. Возможности языка программирования в сочетании с модулями анализа данных делают его мощным оружием в арсенале любого аналитика. 2.1.2. Появление Python' Язык Python был придуман в конце 1980-х гг. Гвидо ван Россумом, сотрудником Centrum Wiskunde & Informatica (CWI) в Нидерландах, как преемник языка АВС. Его реализация началась в декабре 1989 г. Ван Россум был ведущим разработчиком Python до 12 июля 2018 г., после чего ушел в «отпуск на неопределенный срок» и сложил с себя обязательства «пожизненного самоизбранного диктатора в королев­ стве Python» (именно так его прозвали в сообществе за его работу в качестве глав­ ного лица, принимающего решения по проекту). В январе 2019 г. активные разра- 1 Wikipedia, 2020 (https://en.wikipedia.org/w/index.php?title=History_of_Python) [50].
Введение в Python | 53 ботчики ядра Python избрали Бретта Кэннона, Ника Коглана, Барри Варшаву, Кэрол Виллинг и Гвидо ван Россума в «Руководящий совет», который возглавил проект. 16 октября 2000 г. был выпущен Python 2.0, в котором появилось множество новых базовых функций, включая сборщик мусора с обнаружением циклических ссылок и поддержку Unicode. 3 декабря 2008 г. был выпущен Python 3.0. Это была сильно измененная версия языка, не имеющая полной обратной совместимости. Многие из его основных функций были воспроизведены в версиях Python 2.6.x и 2.7.x. В релиз Python 3 в числе прочего входила утилита 2to3, которая автоматизировала (по крайней мере частично) перевод кода из Python 2 в Python 3. Дата прекращения поддержки Python 2.7 была первоначально установлена 2015 годом, но позже была перенесена на 2020 год из-за опасений того, что боль­ шая часть существующего кода на Python 3 не переносится. В январе 2017 г. Google объявила о работе над транс-компилятором из Python 2.7 в Go для повышения про­ изводительности при параллельных нагрузках. Кстати, язык назван в честь шоу на канале ВВС «Летающий цирк Монти Пайтона» (Monty Python’s Flying Circus) и co змеями никак не связан. Ссылки на скетчи Мон­ ти Пайтона в документации не только разрешены, но и приветствуются!1 2.1.3. Python и другие языки программирования2 Во время работы с компьютерами и разным программным обеспечением вы можете столкнуться с тем, что приходится выполнять немало повторяющейся и, следова­ тельно, времязатратной работы. Всегда хочется автоматизировать такую работу, на которую тратится столько лишнего времени. Например, вы можете выполнить по­ иск и замену в большом количестве текстовых файлов или сложным образом пере­ именовать и переупорядочить множество файлов с фотографиями. Возможно, вы захотите написать небольшую настраиваемую базу данных, специализированное приложение с графическим интерфейсом или простую игру. Если вы профессиональный разработчик программного обеспечения, вам, возмож­ но, приходится поработать с библиотеками на C/C++/Java, и вы видите, что обыч­ ный цикл записи/компиляции/тестирования/повторной компиляции слишком мед­ ленный. Может быть, вы пишете набор тестов для такой библиотеки, и это вам по­ рядком надоело. Для некоторых из этих задач можно написать shell-скрипт для UNIX или bat-файл для Windows, но эти способы лучше всего подходят для перемещения файлов и из­ менения текстовых данных, а не для приложений с графическим интерфейсом и уж точно не для игр. Вы можете написать программу на C/C++/Java, но разработка даже первого чернового варианта программы может занять немало времени. Python 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21]. 2 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
54 | Гпава 2 проще в использовании, доступен в операционных системах Windows, MacOS и UNIX и позволяет выполнить работу быстрее. Python прост в использовании, но при этом это настоящий язык программирования, в котором есть гораздо более мощный инструментарий для создания больших про­ грамм, чем могут предложить shell-скрипты или bat-файлы. С другой стороны, в Python также реализовано больше проверок ошибок, чем в С, и, как в любом языке высокого уровня, в нем есть встроенные высокоуровневые типы данных, такие как гибкие массивы и словари. Многие вещи на Python делают­ ся столь же просто, как и на Awk или даже на Perl, но за счет более общих типов данных Python оказывается применим к гораздо более широкому диапазону задач. Python позволяет разделять программу на модули, которые можно повторно ис­ пользовать в других программах на Python. В нем есть большой встроенный набор стандартных модулей, которые можно использовать в качестве основы для своих программ или в качестве примеров для начала обучения программированию на Python. В этих модулях реализован файловый ввод-вывод, системные вызовы, соке­ ты, а также инструменты для создания графических пользовательских интерфейсов, такие как Tkinter. Python — это интерпретируемый язык, позволяющий значительно сэкономить вре­ мя при разработке программы, поскольку компиляция и связывание в нем не вы­ полняются. Интерпретатор можно использовать в интерактивном режиме, что по­ зволяет легко экспериментировать с функциями языка, писать одноразовые про­ граммы или тестировать функции во время нисходящей разработки программы. А еще это удобный настольный калькулятор. Python позволяет писать программы компактно и читабельно. Программы, напи­ санные на Python, обычно намного короче таких же программ на С, C++ или Java по нескольким причинам. ♦ Типы данных высокого уровня позволяют записывать сложные операции в одну строку. ♦ Группировка операторов выполняется с помощью отступов, а не с помощью скобок в начале и конце блока. ♦ Объявление переменных или аргументов не требуется. Python является расширяемым: если вы знаете язык С, то можете добавить в интер­ претатор новую встроенную функцию или модуль, который бы выполнял важные с точки зрения производительности части кода с максимальной скоростью или свя­ зывал программы на Python с библиотеками, доступными в двоичной форме (например, графическими библиотеками конкретного производителя). После под­ ключения вы можете связать интерпретатор Python с приложением, написанным на С, и использовать его как расширение или командный язык для этого приложения. Не стоит переживать, если многие из терминов, которые прозвучали выше, ни о чем вам не говорят или пока неясны. Все эти термины мы изучим по мере необ­ ходимости. Здесь же мы пока просто привели сравнение различных языков про­ граммирования, чтобы убедиться, что мы на правильном пути.
Введение в Python | 55 2.1.4. Философия Python Основная философия языка кратко изложена в документе Zen of Python', в котором можно найти такие афоризмы, как: ♦ Красивое лучше, чем уродливое. ♦ Явное лучше, чем неявное. ♦ Простое лучше, чем сложное. ♦ Сложное лучше, чем запутанное. ♦ Читаемость имеет значение. 2.2. Преимущества Python по сравнению с другими языками 2.2.1. Простота Python по простоте напоминает «дисциплинированный английский». То есть это не какой-то чужеродный язык, который нормальный человек не может понять. Но в то же время для его применения требуется некоторая дисциплина. Чтение кода на Python похоже на чтение на английском. Простота — одна из основных сильных сторон Python. Это позволяет нам больше сосредоточиться на решении, а не на синтаксисе языка программирования. Разве это не здорово? 2.2.2. Легкость в изучении Как вы увидите далее в книге, Python — чрезвычайно простой язык для начинаю­ щего. Его синтаксис очень прост. 2.2.3. Свободный и открытый исходный код Python распространяется бесплатно. Как мы увидим в процессе загрузки и установ­ ки Python, все делается совершенно бесплатно. И не будет никаких скрытых плате­ жей за использование или распространение вашей работы. Python распространяется по модели FLOSS (Free/Libre and Open Source Software). Проще говоря, вы можете открыто распространять дубликаты этого продукта, чи­ тать его исходный код, вносить в него изменения и использовать его в бесплатных проектах. Есть целое сообщество FLOSS, которое взаимодействует между собой и обменивается информацией. Это одна из причин, почему Python нам подходит, — этот язык был создан и постоянно совершенствуется сообществом, которое желает сделать его как можно лучше. ' https://en.wikipedia.org/wiki/Zen_of_Python (Wikipedia, 2020).
56 | Гпава 2 2.2.4. Высокоуровневость Язык программирования высокого уровня — это язык, в котором вам не приходит­ ся думать о множестве деталей, которые нужны при использовании языка про­ граммирования низкого уровня. Например, в Python не приходится беспокоиться об управлении памятью, используемой вашей программой. Проще говоря, языки низ­ кого уровня ближе к аппаратному обеспечению, чем языки программирования вы­ сокого уровня, которые ближе к человеческим языкам. 2.2.5. Портативность Портативность означает, что Python можно использовать на разных типах машин, независимо от аппаратных средств или ограничений операционной системы. Бла­ годаря открытому исходному коду Python был перенесен на многие платформы, и его можно использовать в Windows, GNU/Linux, Macintosh, Solaris, Palm OS, PlayStation, Sharp Zaurus, Windows СЕ и PocketPC! 2.2.6. Интерпретируемость Когда вы пишете программу на языке С или C++, она преобразуется из исходного языка, т. е. из кода на С или C++, в машинный код (состоящий из 0 и 1), потому что именно такой язык понимает компьютер. Этот процесс выполняется с помощью компилятора. Когда программа запускается, программное обеспечение компонов­ щика копирует программу в память и запускает ее. Python не требует компиляции в двоичный код, а ваша программа запускается пря­ мо из исходного кода. Внутри Python преобразует исходный код в промежуточную форму, называемую байт-кодами, затем переводит ее на родной язык компьютера и запускает. Что в этом хорошего для нас? ♦ Не нужно беспокоиться о компиляции программы. ♦ Не нужно думать о том, связаны и загружены ли нужные библиотеки. ♦ Программы Python получаются намного более портативными, и для запуска программы на другом компьютере достаточно просто скопировать ее. Python — это самый быстроразвивающийся язык программирования в 2020 году, поэтому недостатка в интерпретаторах у него нет. Давайте бегло пробежимся по ним. 2.2.7. Интерпретаторы Python1 Что такое интерпретатор? По определению интерпретатор — это разновидность компьютерной программы, которая непосредственно выполняет инструкции, написанные на каком-либо языке 1 Kaushik, 2020 (https://hackr.io/blog/python-interpreters ) [10].
Введение в Python | 57 программирования или языке сценариев. Под непосредственным выполнением подразумевается, что предварительная компиляция кода в программу на машинном языке не требуется. Давайте кратко рассмотрим 7 самых популярных интерпретаторов Python. 2.2.7.1. IPython ТРГуГ Когда вы устанавливаете Python, с ним также устанавливается интер­ JL I Ly J • Interactive Computing претатор по умолчанию. Вы можете запустить интерпретатор по умолчанию, набрав команду python в командной строке вашего компьютера. После загрузки интерпретатора код на Python можно выпол­ нять в командной строке. Этот интерпретатор используется по умолчанию, но у него есть свои ограничения. Например, в нем нет отступов, выделения синтаксиса цветом, дополнения табуляции и многого другого, что есть в других интерпретаторах. ipython IPython — это альтернативный интерпретатор Python. Это интерактивная оболочка, которая используется для вычислений на Python. В ней гораздо больше полезных функций по сравнению с интерпретатором Python, используемым по умолчанию. Позже в этой главе будет приведено пошаговое руководство о том, как установить Python с использованием дистрибутива Anaconda, и там будет установлен именно IPython. При установке Python через Anaconda автоматически устанавливается IPython. В комплекте с IPython идет редактор Jupyter Notebook— один из наиболее часто используемых начинающими программистами инструментов. 2.2.7.2. CPython Это стандартная и наиболее широко используемая реализация языка программирования Python. Напи­ санный на С и Python, интерпретатор CPython содер­ жит много внешних функций С и связан с другими языками программирования. (Поддержка — до Python 3.7) CPython можно в какой-то степени считать компиля­ тором, поскольку перед интерпретацией он преобразует код Python в байт-код. В нем используется GIL (глобальная блокировка интерпретатора), которая ограни­ чивает возможности интерпретатора, поскольку она отключает параллельные пото­ ки Python в рамках одного процесса. Будучи эталонной реализацией Python, CPython поддерживает максимальную со­ вместимость с пакетами Python и модулями расширения С. Таким образом, все вер­ сии языка программирования Python реализованы на С. CPython— единственный вариант использования пакетов Python, которому для правильной работы нужны расширения С. Использование CPython совершенно не-
58 | Гпава 2 обходимо, если ваша программа на Python должна охватить максимально широкую аудиторию. 2.2.7.3. IronPython IronPython IronPython — это реализация языка программирования Python для платформы .NET, в которой используются библиотеки Python и .NET. Этот интерпретатор может (Поддержка — до Python 2.7) предоставлять код Python другим языкам, относящим­ ся к платформе .NET. В IronPython есть поддержка динамической компиляции и встроенная интерактив­ ная консоль. Использование интерпретатора Python позволяет скриптам Python взаимодействовать с объектами .NET. IronPython напрямую интегрируется в среду разработки Visual Studio. 2.2.7.4. Jython Ранее известная как JPython, реализация Jython работает на платформе Java. Это сочетание Java и Python преобразует код Python в байт-код Java и, следовательно, позволяет за­ пускать код Python на любой машине, на которой установ­ лена JVM. Jython обеспечивает поддержку как статической, так и ди(Поддержка — намической компиляции. Важной особенностью этого инД° Python 2.7) терпретатора Python является то, что он позволяет импор­ тировать, а также использовать любые классы Java так, словно это модуль Python. Если вам требуется взаимодействие с существующим кодом на Java или нужно на­ писать код Python для JVM, Jython — ваш кандидат. 2.2.7.5. РуРу РуРу— это быстрая и совместимая альтернативная реа­ лизация языка программирования Python. Этот интерпре­ татор Python реализован в RPython, который представляет собой ограниченное статически типизированное подмножество языка программирования Python. Благодаря JIT-компилятору РуРу поддерживает сервер- @)РУРУ (Поддержка — до Python 2.7, Python 3.5 и Python 3.6) ные части С, CLI и JVM. Основная цель РуРу — обеспе­ чить максимальную совместимость с эталонной реализацией CPython и в то же время увеличить производительность. РуРу используется разработчиками Python, которые хотят увеличить производи­ тельность некоторых видов кода Python. Согласно информации с официального сайта РуРу (https://speed.pypy.org) этот интерпретатор Python примерно в 4.4 раза быстрее CPython.
Введение в Python | 59 2.2.7.6. PythonNet PythonNet позволяет выполнить почти бесшовную интеграцию Python с .NET CLR. Подход этого интерпретатора можно счи­ тать противоположным тому, которому следует IronPython. При использовании вместе с Mono, PythonNet позволяет встро­ енным в операционные системы установкам Python (кроме Windows) работать в среде .NET. PythonNet можно использо­ вать совместно с IronPython без каких-либо проблем. (Поддержка — от Python 2.6 до Python 3.5) 2.2.7.7. Stackless Python CPython и другие популярные интерпретаторы Python для управления стеком используют язык С. Но к интерпретатору Stackless Python это не относится. Хотя в Stackless Python используется стек С, между вызовами функций он очищается. Следовательно, интерпретатор Python в работе со стеком не зависит от вызова С. Как и CPython, Stackless Python написан с использованием С и Python. (Поддержка — до Python 3.7) Помимо поддержки потоков, у Stackless Python есть поддержка каналов связи, сопрограмм, предварительно скомпилированных двоичных файлов, циклического планирования, сериализации задач и тасклетов. Возможно, самая важная особенность Stackless Python — это наличие микропото­ ков. Эта возможность помогает избежать значительной части накладных расходов, связанных с обычными потоками операционной системы. * * * Этот обзор интерпретаторов должен был дать вам лучшее понимание того, какие существуют интерпретаторы и чем они отличаются. Мы не будем использовать их напрямую, поэтому думать о том, какой из них надо установить, не нужно. Но ведь любопытно, не так ли? Мы будем использовать дистрибутив Anaconda, который представляет собой луч­ ший инструмент для новичков (и даже продвинутые пользователи признают его универсальность и полезность). В дистрибутив Anaconda входит интерпретатор IPython. Но, опять же, думать об этом не нужно, т. к. интерпретатор будет сразу встроен в Jupyter Notebook или консоль, в зависимости от того, что вы будете использовать. 2.2.8. Объектная ориентированность1 Python поддерживает процедурно-ориентированное программирование, а также объектно-ориентированное программирование. В процедурно-ориентированных языках программа состоит из процедур или функций, в которых заключены много1 Swaroop, 2003 (https://python.swaroopch.com/) [39].
60 | Гпава 2 кратно используемые части программы. В объектно-ориентированных языках про­ грамма построена на объектах, которые включают в себе данные и функциональ­ ность. В Python очень мощный, но упрощенный стиль объектно-ориентированного программирования, особенно по сравнению с такими крупными языками, как C++ или Java. 2.2.9. Расширяемость1 Если в коде есть критический фрагмент, от которого зависит быстродействие, или вы хотите, чтобы какой-то фрагмент алгоритма был скрыт, вы можете написать эту часть программы на С или C++, а затем использовать ее из программы на Python. Python легко расширяется с помощью кода C/C++/Java и легко встраивается в при­ ложения. 2.2.10. Встраиваемость Код Python можно встраивать в программы на C/C++, что позволяет использовать возможности скриптов. 2.2.11. Внушительные библиотеки Стандартная библиотека Python, которую обычно упоминают как одну из сильней­ ших сторон этого языка, содержит инструменты, подходящие для огромного мно­ жества задач. Для написания приложений, которым требуется выход в Интернет, есть многие стандартные форматы и протоколы, такие как MIME и HTTP. Здесь же вы найдете модули для создания графических пользовательских интерфейсов, под­ ключения к реляционным базам данных, генерации случайных чисел, работы с де­ сятичными дробями произвольной точности, работы с регулярными выражениями и модульного тестирования. По состоянию на март 2018 г. официальный репозиторий для стороннего про­ граммного обеспечения Python под названием PyPI (Python Package Index) содержал более 130 000 пакетов с широким набором функций, в том числе: ♦ графические пользовательские интерфейсы; ♦ веб-фреймворки; ♦ мультимедиа; ♦ базы данных; ♦ сети; ♦ фреймворки тестирования; ♦ автоматизация; ♦ парсинг веб-страниц; ♦ документация; 1 Swaroop, 2003 (https://python.swaroopch.com/) [39].
Введение в Python | 61 ♦ системное администрирование; ♦ научные вычисления; ♦ обработка текста; ♦ обработка изображений. 2.2.12. Python для начинающих1 Python лучше всего подходит для начинающих с минимальным или нулевым опы­ том компьютерного программирования. Студентов многих учебных заведений по-прежнему начинают учить программиро­ ванию с процедурных и статически типизированных языков, таких как Pascal, С или подмножество C++ или Java. Возможно, в качестве первого языка стоит начать с Python. У Python очень простой и последовательный синтаксис и богатая стан­ дартная библиотека, и, что наиболее важно, использование Python в начальном курсе программирования позволяет студентам сосредоточиться на важных навыках программирования, таких как декомпозиция задач и проектирование типов данных. Используя Python, студенты могут быстро познакомиться с базовыми понятиями, такими как циклы и функции. Возможно, даже удастся быстро перейти к работе с пользовательскими объектами. Для студента, который никогда раньше не программировал, использование стати­ чески типизированного языка кажется неестественным. Такой язык несет с собой дополнительные сложности, которые приходится изучать, а это замедляет темп обучения. Студенты пытаются научиться думать как компьютер, декомпозировать задачи, разрабатывать согласованные интерфейсы и инкапсулировать данные. Хотя обучение использованию статически типизированного языка важно в долгосрочной перспективе, для студентов первого курса программирования это решение может быть не самым лучшим. У Python есть и другие преимущества, которые делают его хорошим языком для первых шагов в программировании. Как и в Java, в Python имеется огромная стан­ дартная библиотека, что позволяет создавать полезные проекты уже на самых ран­ них этапах обучения. Возможные темы проектов не ограничиваются стандартным калькулятором с четырьмя функциями или программами для простого подсчета финансов. Используя стандартную библиотеку Python, студент может поработать над приближенным к реальному приложением, параллельно изучая основы про­ граммирования. Использование стандартной библиотеки также учит студентов по­ вторному использованию кода. Сторонние модули, такие как PyGame, также помо­ гают студентам расширить свои горизонты. Интерактивный интерпретатор Python позволяет студентам пробовать разные функции языка в процессе программирования. В одном окне можно открыть запу­ щенный интерпретатор, а в другом писать код. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
62 | Гпава 2 2.3. Версии Python1 2.3.1. Python 2 Вышедший в конце 2000 г. Python 2 характеризовался более прозрачным и вместе с тем полным процессом разработки языка, чем в более ранних версиях Python. Появились документы PEP (Python Enhancement Proposal), в которых излагаются информация по Python и описание новых функций. Кроме того, в Python 2 появи­ лось множество других функциональностей, например сборщик мусора с обнару­ жением циклов для автоматизации управления памятью, расширенная поддержка Unicode для стандартизации символов и списочные включения. Постепенно в Python 2 добавлялись и другие функции, в том числе объединение типов и клас­ сов Python в одну иерархию в версии Python 2.2. 2.3.2. Python 2.7 После выпуска Python 3.0 в 2008 г., 3 июля 2010 г. вышел Python 2.7, который пла­ нировался как последний выпуск в линейке версий 2.x. Целью Python 2.7 было об­ легчить пользователям Python 2.x переход на Python 3 и предоставить совмести­ мость между этими версиями. Поддержка совместимости заключалась в добавление в версию 2.7 новых модулей, таких как unittest для автоматизации тестирования, argparse для анализа параметров командной строки, а также более удобные классы в коллекциях. Из-за уникального положения Python 2.7 как промежуточного звена между более ранними итерациями Python 2 и Python 3.0 эта версия по-прежнему остается очень популярной из-за ее совместимости со многими проверенными вре­ менем библиотеками. Сегодня, говоря о Python 2, мы обычно имеем в виду версию Python 2.7, поскольку именно она используется чаще всего. 2.3.3. Python 3 Python 3 считается будущим Python, и именно эта версия языка в настоящее время находится в разработке. Python 3 был выпущен в конце 2008 г. после масштабной переработки, и в нем были устранены и исправлены внутренние недостатки, при­ сущие более ранним версиям языка. Основное внимание при разработке Python 3 уделялось очистке кодовой базы и устранению избыточности, чтобы для каждой задачи существовал лишь один способ ее выполнения. К основным изменениям в Python 3.0 можно отнести превращение оператора print во встроенную функцию, улучшение методики деления целых чисел и расширение поддержки Unicode. Сна­ чала Python 3 довольно медленно проникал в работу программистов, т. к. он не был обратно совместим с Python 2, и людям приходилось выбирать, какую версию язы­ ка использовать. Кроме того, многие библиотеки пакетов все еще поддерживали только Python 2. Однако когда разработчики языка объявили, что поддержка 1 Tagliaferri, 2016 (https://www.digitalocean.com/community/tutorials/python-2-vs-python-3-practicalconsiderations-2) [40].
Введение в Python | 63 Python 2 в какой-то момент прекратится, многие библиотеки были перенесены на Python 3. Это позволило ускорить принятие Python 3, что нетрудно видеть по коли­ честву доступных пакетов. На данный момент 339 из 360 наиболее популярных пакетов поддерживаются в Python 3. 2.3.4. Ключевые отличия версий У Python 2.7 и Python 3 немало схожих возможностей, но не следует рассматривать эти языки как полностью взаимозаменяемые. Конечно, можно писать хороший код и полезные программы в любой версии, но важно помнить о различиях в синтакси­ се и обработке кода. 2.4. Как установить и использовать Python Последнюю версию автономного дистрибутива Python можно загрузить по сле­ дующей ссылке: https://www.python.org/downloads Но так вы установите только Python с его интерпретатором по умолчанию, а нам нужно еще загрузить и установить IDE, консоль Python, Jupyter Notebook, а также добавить отдельные пакеты Python. Для решения этой задачи есть более эффективный способ, которым мы и восполь­ зуемся. Единственный минус этого подхода заключается в том, что при автономной установке Python он занимает намного меньше места в памяти (очевидно, из-за отсутствия другого программного обеспечения). Мы будем использовать дистрибутив Anaconda. Давайте загрузим и установим его. 2.4.1. Дистрибутив Anaconda Дистрибутив Anaconda — это самый простой и наиболее часто используемый спо­ соб установки Python и других необходимых пакетов. Он находится в свободном доступе и прост в установке. Дистрибутив Anaconda с открытым исходным кодом — это самый простой способ выполнять анализ данных с помощью языков Python/R и машинное обучение в Linux, Windows и MacOS. У дистрибутива больше 11 миллионов пользователей по всему миру, он является отраслевым стандартом в области разработки, тестиро­ вания и машинного обучения и позволяет специалистам по данным: ♦ быстро загрузить более 1500 пакетов Python/R, предназначенных для задач ана­ лиза данных; ♦ управлять библиотеками, зависимостями и средами с помощью Conda; ♦ разрабатывать и обучать модели машинного обучения и глубокого обучения с помощью пакетов Scikit-learn, TensorFlow и Theano; ♦ выполнять эффективный и масштабируемый анализ данных с помощью Dask, NumPy, Pandas и Numba;
64 | Гпава 2 ♦ визуализировать результаты с помощью Matplotlib, Bokeh, Datashader и Holo­ views. 2.4.2. Почему именно Anaconda? В дистрибутиве Anaconda дополнительно реализовано много полезных функциональностей, которые упрощают работу начинающим программистам. ♦ Возможность выбора и установки нужной вам версии Python. ♦ Возможность установки/обновления пакетов совершенно независимо от систем­ ных библиотек или прав администратора. ♦ Инструмент Conda устанавливает бинарные пакеты и не требует компиляции ресурсов, таких как pip, что тоже удобно, если вы ограничены в правах установ­ ки необходимых библиотек. ♦ Частичное избавление от головной боли на предмет того, какая версия пакета X совместима с какой версией пакета Y, когда оба они требуются для установки пакета Z. ♦ Возможность загрузки либо полной версии, с NumPy, Scipy, PyQt, Spyder IDE и т. д., либо в минимальной комплектации (miniconda), где вы можете выбрать только нужные компоненты. ♦ Отсутствие риска испортить системные библиотеки. 2.4.3. Установка Anaconda в Windows' 1. Скачайте установочный файл Anaconda (https://www.anaconda.eom/download/#windows ). 2. Дважды щелкните по нему, чтобы запустить. Примечание Во избежание проблем с правами допуска не запускайте установщик из папки Из­ бранное. Если у вас возникнут проблемы во время установки, временно отключите антивирус­ ное программное обеспечение, а затем снова включите его после завершения уста­ новки. Если установка была выполнена для всех пользователей операционной систе­ мы, попробуйте удалить Anaconda и переустановить его только для своего пользова­ теля, а затем повторите попытку. 3. Нажмите кнопку Next. 4. Прочтите условия лицензионного соглашения и нажмите кнопку I Agree. 5. Выберите опцию установки Just Me, если не требуется установка для всех поль­ зователей (для чего требуются права администратора Windows), и нажмите кнопку Next. 6. Выберите папку для установки Anaconda и нажмите кнопку Next (рис. 2.2). 1 Anaconda, Installing on Windows, 2020 (https://docs.anaconda.com/anaconda/install/windows/ ) [3].
Введение в Python 65 X О Anaconda3 2019,03 (64-bit) Setup О | Choose Install Location ANACON DA Choose the folder in which to install Anaconda3 2019.03 (64-bit). Setup wit install Anaconda3 2019.03 (6-3-txt) in the folowing folder. To install in a different folder, dfck Browse and select another folder. Click Next to continue. Destination Folder 1 Space requred: 3.1GB Space available.' 43.3GB Anaconda, Inc.---------------<Badt | Next» Cancel J Рис. 2.2. Выбор папки для установки Anaconda Примечание Установите Anaconda в папку, путь к которой не содержит пробелов и символов Unicode. Не устанавливайте дистрибутив от имени Администратора, если таковое не требуется. 7. Выберите, следует ли добавить Anaconda в переменную среды PATH. Мы рекомендуем не делать этого, поскольку это может помешать работе другого программного обеспечения (рис. 2.3). Вместо этого лучше запускать Anaconda, открыв Anaconda Navigator или Anaconda Prompt из меню Пуск. 8. Выберите, нужно ли использовать Anaconda в качестве версии Python по умол­ чанию. Если вы не планируете устанавливать и запускать несколько версий Anaconda или несколько версий Python, установите значение по умолчанию. 9. Нажмите кнопку Install. Если вы хотите посмотреть, какие пакеты устанавли­ вает Anaconda, нажмите кнопку Show Details. 10. Нажмите кнопку Next. 11. Необязательно: чтобы установить PyCharm для Anaconda, перейдите по ссылке https://www.anaconda.com/pycharm . А если вы хотите установить Anaconda без PyCharm, нажмите кнопку Next (рис. 2.4). 12. После успешной установки вы увидите заключительно диалоговое окно «Thanks for installing Anaconda» («Спасибо за установку Anaconda») (рис. 2.5). Если вы хотите узнать больше об Anaconda Cloud и о том, как начать работу с Anaconda, установите флажки Learn more about Anaconda Cloud и Learn how to get started with Anaconda. Нажмите кнопку Finish.
66 | Гпава 2 □ О Anaconda? 2019.03 (64-bit) Setup X Advanced Installation Options ANACONDA Customize how Anaconda integrates with Windows Advanced Options □ Add Anaconda to my PATH environment variable Not recommended. Instead, open Anaconda with the Windows Start menu and select "Anaconda (64-bit)". This "add to PATH" option makes Anaconda get found before previously mstaBed software, but may cause problems requiring you to uninstal and reinstall Anaconda. 0 Register Anaconda as my default Python 3.7 This wl alow other programs, such as Python Tools for Visual Studio PyCharm, Wing IDE, PyDev, and MSI binary padcages, to automaticaly detect Anaconda as the primary Python 3.7 on the system. Anaconda,Inc. Рис. 2.3. Варианты установки Anaconda X О Anaconda? 2019.0? (64-bit) Setup О Anaconda? 2019.03 (64-bit) ANACONDA Anaconda + JetBrains Anaconda and JetBrams are working together to bring you Anaconda-powered environments tightly integrated in the PyCharm IDE. PyCharm for Anaconda is available at https://www.anaconda.com/pycharm О ANACONDA. Anaconda, Inc.-------------------------------------------------------------------------------------------------------------------- Рис. 2.4. Ссылка на PyCharm при установке Anaconda После завершения установки проверьте, все ли установилось, открыв программу Anaconda Navigator. Для этого в меню Пуск вашей ОС Windows выберите ярлык Anaconda Navigator из раздела Недавно добавленные или введите Anaconda Navigator в строке поиска (рис. 2.6). Если Anaconda Navigator запустится, то дист­ рибутив Anaconda установлен успешно. Если нет, убедитесь, что вы выполнили все указанные выше действия, а также перейдите на страницу справки.
Введение в Python 0 AnacondaB 2019.03 (64-bit) Setup Thanks for installing Anaconda3! Anaconda is the most popular Python data science platform. ANACONDA. Share your notebooks, packages, projects and environments on Anaconda Cloud! 0 Learn more about Anaconda Cloud 0 Learn how to get started with Anaconda Рис. 2.5. Установка завершена Рис. 2.6. Запуск Anaconda Navigator из системного меню Windows | 67
68 | Гпава 2 Ниже приведены ссылки на документацию по установке Anaconda для различных операционных систем: https://docs.anaconda.com/anaconda/install/windows/; https://docs.anaconda.com/anaconda/install/mac-os/; https://docs.anaconda.com/anaconda/install/linux/. 2.4.4. Установка Anaconda в MacOS Вы можете установить Anaconda, используя либо графический мастер установки, либо с помощью командной строки (ручной способ), как описано далее. Если вы не уверены, каким путем пойти, выберите графическую установку. Установка на MacOS с помощью мастера: 1. Загрузите графический установщик для MacOS (https://www.anaconda.com/ downloads#macos) нужной версии Python. 2. Дважды щелкните по загруженному файлу и нажмите кнопку Continue, чтобы начать установку. 3. Ответьте на запросы в окнах Introduction, Read Me и License. 4. Нажмите кнопку Install, чтобы установить Anaconda в домашний каталог поль­ зователя (рекомендуется) (рис. 2.7). Рис. 2.7. Установка Anaconda в MacOS 1 Anaconda, Installing on MacOS, 2020 (https://docs.anaconda.com/anaconda/install/mac-os/ ) [2].
Введение в Python | 69 Или нажмите кнопку Change Install Location, чтобы выполнить установку в другом месте (не рекомендуется). 5. В окне Destination Select выберите пункт Install for me only (рис. 2.8). Примечание Если вы получите сообщение с текстом «You cannot install Anaconda in this location», повторно выберите вариант Install for me only. Рис. 2.8. Установка только для текущего пользователя в MacOS 6. Нажмите кнопку Continue. 7. Необязательно: чтобы установить PyCharm для Anaconda, перейдите по ссылке https://www.anaconda.com/pycharm . Или, чтобы установить Anaconda без PyCharm, нажмите кнопку Continue (рис. 2.9). 8. При успешной установке появится следующее окно (рис. 2.10). После завершения установки проверьте, все ли установилось, открыв программу Anaconda Navigator. В Launchpad выберите Anaconda Navigator. Если открывает­ ся приложение, вы успешно установили Anaconda. Если Navigator запустится, то дистрибутив Anaconda установлен успешно. Если нет, убедитесь, что вы выполни­ ли все указанные выше действия, а затем перейдите на страницу справки. Примечание Для получения дополнительной информации об использовании Anaconda Navigator перейдите по ссылке https://docs.anaconda.com/anaconda/navigator/ .
70 | Гпава 2 Рис. 2.9. Ссылка на PyCharm при установке Anaconda в MacOS Рис. 2.10. Установка Anaconda в MacOS завершена
Введение в Python | 71 2.5. Запуск Python через командную строку Командная строка — это самый эффективный способ запуска на компьютере любо­ го программного обеспечения, включая Python (независимо от того, MacOS, Windows или Linux вы используете), но мы рассмотрим его всего лишь один раз, т. к. изучение командной строки выходит за рамки этой книги. Освоить работу с компьютером через командную строку — это само по себе круто, но у нас не про­ сто так есть графический интерфейс пользователя (GUI). С его помощью новые пользователи и те, кто не так хорошо разбирается в компьютерах, могут полноцен­ но использовать все возможности компьютеров. Итак, мы рассмотрим, как Python работает в командной строке, а затем перейдем к работе с консолью Python (IPython), Spyder IDE или c Jupyter Notebook. Командная строка— это приложение, которое позволяет запускать команды для просмотра папок и файлов, выполнения скриптов и, конечно, для работы с Python. Консоль (она же терминал или командная строка) — это текстовый способ взаи­ модействия с вашей ОС, точно такой же, по существу, как рабочий стол и мышь, которые тоже являются способом взаимодействия с системой. В MacOS, чтобы открыть приложение Terminal, нужно перейти в Finder, затем от­ крыть приложения. Зайдите в раздел утилит и запустите Terminal. Вы также можете сделать это с помощью клавиш, нажав <Command> и пробел, а затем набрав «Terminal» и нажав клавишу <Enter>. В Windows аналогичное приложение называется командной строкой (cmd). Также в любой операционной системе можно открыть приложение Anaconda Prompt— командная строка Anaconda (см. выделенное поле в левом списке на рис. 2.11). Давайте откроем командную строку Anaconda Prompt и попробуем выполнить парочку команд. Командная строка Anaconda выглядит и работает так же, как и обычная командная строка. Вы увидите папку, где установлена Anaconda и соответственно интерпрета­ тор Python. Если вы выбрали при установке «для данного пользователя» (а не для всех пользователей), запрос будет выглядеть следующим образом: С:\И8егз\вашеимя> Запустите интерпретатор Python. Для этого просто введите команду жмите клавишу <Enter>. python и на­ Давайте остановимся и посмотрим, какую информацию командная строка нам вывела. Мы видим, какая версия Python у нас установлена и готова к использованию. Кроме того, приглашение ввода стало выглядеть иначе: Теперь мы находимся в приглашении Python (рис. 2.12). Это означает, что компью­ тер готов к нашим распоряжениям.
Acrobat Reader DC Adobe Adobe Acrobat 7.0 Professional Sunday We speak 12 Yahoo О Xbox Console- Groove Music Movies & TV Office Lens Adobe Designer 7.0 Й i Adobe Digital Editions 4.5 Anaconda Powershell Prompt (Ana... 86' Anaconda Prompt (Anaconda3) D Jupyter Notebook (Anaconda3) В 94‘ New Delhi Microsoft Re... Sway Alarms & Clock Voice Recorder Reset Spyder Settings (AtiacondaS) Spyder (Anaconda3) © (!) В Aruba Networks в 0 P (Type here to search й: 05 Bl & Xg — л| ' pi Рис. 2.11. Командная строка Anaconda в меню Пуск Рис. 2.12. Запуск Python из командной строки Anaconda Теперь давайте попробуем решить на Python простую математическую задачу — сложить два числа. Попробуем на обычном английском задать компьютеру вопрос (сколько будет 2 плюс 2): what is two plus two? Спросим Python. (Было бы хорошо, если бы у вас тоже было открыто окно команд­ ной строки и вы выполняли команды вместе со мной.) Вы получите сообщение: SyntaxError: invalid syntax
Введение в Python | 73 Напомним, что синтаксис— это правила языка программирования. Синтаксиче­ ские ошибки возникают в случаях, когда вы пишете код, нарушающий эти самые правила. Сейчас мы написали код на простом английском языке, но интерпретатор не понимает английского, он понимает только Python. Попробуем еще раз. На этот раз наберите (и не забудьте нажать <Enter> для запуска команды): 2 + 2 В ответ получаем 4. Все получилось, потому что выражение 2 + 2 для Python до­ пустимо и понятно (рис. 2.13). ■Anaconda Prompt (Anacondas) - python —OX (base) C:\Users\nilabhnishchhal>python Python 3.7.6 (default, Dan 8 2020, 20:23:39) [HSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on Win32 Гуре "help", "copyright", "credits" or "license" for more information. >>> what is two plus two? File "<stdin>", line 1 what is two plus two? SyntaxError: invalid syntax »> 2+2 Рис. 2.13. Запуск кода Python из командной строки Теперь закройте окно командной строки с помощью команды exit о. Теперь давай­ те перейдем к изучению приложений, которые установились вместе с Anaconda, и тем самым продвинемся в вашем обучении. Примечание Первая команда exit о закроет интерпретатор Python (»>), а еще одна команда закроет окно командной строки. exit 2.6. Приложения Anaconda На рис. 2.14 показано, как выглядит окно Anaconda Navigator после открытия. В нем вы видите несколько приложений, используемых для тех или иных действий. Но мы начнем с 3 основных программ, которые используются чаще всего: ♦ Консоль IPython; ♦ Spyder; ♦ J upyter N orebook. 2.7. Консоль IPython Qt1 Это обладающая немалыми возможностями консоль, выполненная с помощью Qt, подходящая для работы с ядрами Jupyter, с поддержкой вывода мультимедиа, экспорта сеансов и многих других вещей. 1 IPython, 2020 (https://ipython.Org/ipython-doc/3/interactive/qtconsole.html) [8].
74 | Гпава 2 Консоль Qt— это очень легкое приложение, во многом похожее на командную строку, но с дополнительными функциями, которые можно реализовать только в графическом интерфейсе (рис. 2.15), такими как встраивание рисунков, правиль­ ное многострочное редактирование с подсветкой синтаксиса, подсказки и многое другое. Чтобы поближе познакомиться с этой консолью, наберите команду ?, чтобы уви­ деть краткое описание ее основных функций. В интерфейсе Qt для навигации по тексту используются привязки в стиле emacs. Их на данный момент настроить нельзя. Консоль IPython позволяет выполнять команды, а также вводить, взаимодейство­ вать и визуализировать данные через любое количество полноценных интерпрета­ торов IPython. Каждая консоль выполняется в отдельном процессе, что позволяет запускать скрипты, прерывать выполнение и перезапускать или завершать сессию, не затрагивая другие консоли, и легко тестировать свой код в чистой среде, не пре­ рывая основного сеанса. Примечание Поскольку консоль Qt изо всех сил пытается мимикрировать под командную строку, по умолчанию она сразу же выполняет введенные строки, если те дописаны до конца. Если вы хотите ввести многострочную команду, в конце первой строки вместо клави­ ши <Enter> нажмите комбинацию клавиш <Ctrl>+<Enter>, после чего добавится новая строка для ввода. В любой точке многострочного блока вы можете выполнить его (не переходя в конец блока) с помощью комбинации клавиш <Shift>+<Enter>.
Введение в Python | 75 Рис. 2.15. Консоль Qt для IPython 2.8. Spyder IDE' Spyder представляет собой бесплатную интегрированную среду разработки (IDE), которая входит в состав Anaconda. В ней имеются функции редактирования, инте­ рактивного тестирования, отладки и самоанализа. 1 Spyder, 2018 (https://docs.spyder-ide.org/index.html) [36].
76 | Гпава 2 После установки Anaconda запустите Spyder в Windows, MacOS или Linux. Spyder IDE также предварительно установлена в Anaconda Navigator. Чтобы от­ крыть IDE, на главной странице Navigator щелкните по кнопке Spyder. Spyder — это мощная научная среда, написанная на Python для Python, разработан­ ная учеными, инженерами и аналитиками данных для своих нужд (рис. 2.16). Эта среда отличается уникальным сочетанием функций редактирования, анализа, от­ ладки и профилирования, присущих сложным инструментам разработки, и функ­ ций исследования данных, интерактивного выполнения, глубокой проверки и фан­ тастическими возможностями визуализации, присущих научному программному обеспечению. Кроме того, в Spyder имеется встроенная интеграция со многими популярными научными пакетами, такими как NumPy, SciPy, Pandas, Matplotlib, SymPy и др. Рис. 2.16. Spyder IDE для Python 2.8.1. Компоненты Spyder IDE' В этом разделе будут перечислены основные составляющие среды разработки Spyder IDE. 2.8.1.1. Редактор текста Многоязычный редактор в Spyder содержит множество мощных инструментов для простого и эффективного редактирования кода (рис. 2.17). К важнейшим особенно- 1 Spyder, 2018 (https://docs.spyder-ide.org/index.html) [36].
Введение в Python | 77 стям редактора можно отнести выделение синтаксиса цветом (pygments), анализ кода и стиля в реальном времени (pyflakes и pycodestyle), дополнение строк по за­ просу, подсказки и функции перехода к определению (горе и jedi), обозреватель функций/классов, горизонтальное и вертикальное разделение и многое другое. йг > аа* е и к л.г,- import pandas as pd 258 259class DataSet(pd.Dataf-rame): ny of our supported platforms hl is to download it as part of the En<«K>sulates a dataset ' environment manager to keep it US If in doubt, you should always install Spyder via this method to avoid B-:> unexpected issues we def __ init__ (self, fileLocation *>.< able to provide limited assistant Take the appropriate actions to prepare a wrapped datafraae ft Paramete The .?Ai:krz’,hftaJ(hX.t>.'A,.Z.''.Ki:SAx'.thBX!*41i.tbkiixie.') distribution for Windows filel.oca included with most Python installations these methods 10-1 Spyde iuper().__init__ () dataset - pd.read csv(fileLocation) if on Windows): super().__init__ (data-set./.__ dataset) sei/._list category attributes def prepare dataset(wf /) ime dependencies iaiisllatlon. Aai.tcusii'.'osKL’t: 5Й0 testdataset = DataSet("D<ii:. Ю1 Ж.____________________________ _________ Рис. 2.17. Разделение окна редактора по горизонтали 2.8.1.2. IPython консоль Консоль IPython позволяет выполнять команды, а также вводить, взаимодейство­ вать и визуализировать данные через любое количество полноценных интерпрета­ торов IPython. Каждая консоль выполняется в отдельном процессе, что позволяет запускать сценарии, прерывать выполнение и перезапускать или завершать оболоч­ ку, не затрагивая другие консоли, и легко тестировать свой код в чистой среде, не прерывая основной сеанс. Вы можете использовать сколько угодно консолей IPython, у каждой из которых будут все функции графического интерфейса, выполнение кода по строкам, ячей­ кам или файлам, отображение графики прямо в строке (рис. 2.18). 2.8.1.3. Обозреватель переменных Обозреватель переменных Variable explorer позволяет просматривать содержимое пространства имен (все ссылки на глобальные объекты, такие как переменные, функции, модули и т. д.) текущего сеанса консоли IPython (рис. 2.19) и управлять им с помощью различных встроенных редакторов с графическим интерфейсом.
78 | Гпава 2 Рис. 2.18. IPython-консоль Variable explorer X A S °z a Value Size Type Name array_uint32 uint32 (2. 2. 3) Min: 1 Max: 7 bars conta iner.Ba rCont a iner 20 BarContainer object of matplotlib.container module df OataFrame (3, 2) Column names: bools, ints df_complex DataFrame (5. 1) Column names: 0 filename str 1 C:\Program0ata\Anaconda3\lib\site-packages\matplotlib\mpl-dataV. list_test list 2 [Dataframe, Numpy array] long text str 1 This is some very very very very long text! But Spyder can show- nrows int 1 344 r float64 1 6.469949121504568 radii float64 (20.) Min: 0.031808170090177335 Max: 9.934459607320779 region tuple 2 (slice, slice) (45, 45, 4) Min: 0.0 Max: 1.0 rgb float64 Рис. 2.19. Окно Variable explorer в Spyder IDE A V
Введение в Python | 79 2.8.1.4. Справка Панель справки (Help) используется для поиска, визуализации и отображения под­ робной документации для любого объекта, у которого есть строка документации, включая модули, классы, функции и методы (рис. 2.20). Справку можно получить как путем статического анализа открытых файлов в редакторе, так и путем динами­ ческого просмотра объекта в консоли 1 Python. Рис. 2.20. Окно справки в Spyder IDE Вы можете вызвать справку вручную, введя имя объекта в поле Object в окне справки (по умолчанию открывается сочетанием клавиш <Ctrl>+<I>), или автома­ тически, введя открывающую круглую скобку ( после имени функции или метода. Автоматическую справку можно включить как в редакторе, так и в консоли, зайдя в меню Preferences | Help | Automatic Connections, а также с помощью значка в виде замочка в верхнем правом углу панели Help
80 | Гпава 2 2.9. Jupyter Notebook1 2.9.1. Приложение Jupyter Notebook Этот редактор расширяет консольный подход к интерактивным вычислениям в ка­ чественно новом направлении и сконструирован как веб-приложение, подходящее для записи всего вычислительного процесса: разработки, документирования и вы­ полнения кода, а также передачи результатов. Jupyter Notebook объединяет в себе два компонента: ♦ веб-приложение — инструмент на основе браузера, предназначенный для инте­ рактивного создания документов, сочетающий в себе пояснительный текст, математические вычисления и мультимедийный вывод результатов; ♦ документы Notebook, содержащие все видимое в веб-браузере, включая входные и выходные данные вычислений, пояснительный текст, математические данные, изображения и мультимедийные представления объектов. 2.9.2. Основные возможности веб-приложения Jupyter Notebook позволяет работать с кодом в редакторе, встроенном в окно брау­ зера, с автоматическим выделением синтаксиса цветом, отступами, заполнением табуляцией и анализом. Можно запустить код Python из браузера и получить при­ крепленные к коду результаты вычислений. Отображение результатов вычислений выполняется с использованием мультимедийных форматов, таких как HTML, LaTeX, PNG, SVG и т. д. Например, изображения, генерируемые библиотекой Matplotlib в отличном разрешении для печати, можно встраивать в строку результа­ та (inline). Доступно также форматирование текста в браузере с использованием языка разметки Markdown, что позволяет комментировать код, не ограничиваясь простым текстом в комментариях кода. Кроме того, есть возможность простой ин­ теграции математических формул в ячейки Markdown с помощью LaTeX и визуа­ лизации с помощью MathJax. 2.9.3. Документы Notebook Документы Notebook содержат входные и выходные данные интерактивного сеан­ са, а также дополнительный текст, который добавлен к коду, но не предназначен для выполнения. Таким образом, в файлах Notebook хранится полная запись сеанса работы в веб-приложении, в которую входит исполняемый код с пояснительным текстом, математика и представленные в различных формах результаты. Эти доку­ менты являются внутренними файлами JSON и сохраняются с расширением ipynb. Поскольку JSON — это неформатированный текст, эти файлы также можно вклю­ чать в контроль версий и делиться ими с коллегами. 1 Jupyter, 2015 (https://jupyter-notebook.readthedocs.io/en/stable/notebook.html) [9].
Введение в Python | 81 Документы Notebook можно экспортировать в некоторые статические форматы, например, HTML (для публикации в блогах), Restructured Text, LaTeX, PDF и слайд-шоу, с помощью команды nbconvert. Кроме того, любой документ Notebook формата ipynb, доступный по публичному URL-адресу, можно опубликовать через Jupyter Notebook Viewer (nbviewer). Этот сервис загружает документ Notebook по URL-адресу и отображает его как статиче­ скую веб-страницу. Это позволяет делиться результатами с коллегами или публи­ ковать в открытых источниках, при этом другим пользователям не нужно устанав­ ливать себе Jupyter Notebook. По сути, nbviewer — это тот же nbconvert, но в виде веб-сервиса. 2.9.4. Запуск сервера Notebook Вы можете запустить сервер Notebook из командной строки, используя следующую команду: Jupyter notebook В консоли появится некоторая информация о сервере, после чего в веб-браузере откроется URL-адрес веб-приложения (по умолчанию http://127.0.0.1:8888). Кроме того, вы можете открыть Jupyter Notebook из окна Anaconda Navigator. Главная страница веб-приложения Jupyter Notebook представляет собой дашборд, на котором отображаются созданные документы из вашего каталога (по умолчанию отображается рабочая папка, из которой был запущен сервер Notebook). Вы можете создавать новые документы Notebook на панели управления с помощью кнопки New Notebook или открывать существующие, щелкая по их имени. Вы так­ же можете перетаскивать документы ipynb и стандартные файлы исходного кода Python ру в область списка документов. При запуске сервера Notebook из командной строки вы также можете напрямую открыть конкретный документ, минуя дашборд, с помощью команды: Jupyter notebook my_notebook.ipynb Если расширение файла не задано, по умолчанию добавляется расширение ipynb. Когда у вас открыт документ, с помощью меню File | Open можно открыть новую панель управления в новой вкладке браузера, и там открыть другой документ па­ раллельно или создать новый документ. Примечание Вы можете запустить сразу несколько серверов Notebook, если хотите работать с до­ кументами, расположенными в разных каталогах. По умолчанию первый сервер запус­ кается на порту 8888, а следующие запускаемые серверы ищут свободные порты, близкие к этому порту. Вы также можете явно указать порт с помощью опции —port.
82 | Гпава 2 2.9.5. Создание нового документа Notebook Новый документ можно создать либо на панели управления, либо с помощью пунк­ та меню File | New. Новый документ Notebook создается в том же каталоге и откро­ ется в новой вкладке браузера. Кроме того, он появится в списке документов на панели управления. 2.9.6. Открытие документа Notebook Каждому открытом документу соответствует один интерактивный сеанс, подклю­ ченный к ядру, которое будет выполнять пользовательский код и возвращать ре­ зультаты. Это ядро остается активным при закрытии окна браузера, и повторное открытие того же документа с панели управления приведет к повторному подклю­ чению веб-приложения к тому же ядру. На панели управления у документов с ак­ тивным ядром отображается кнопка Shutdown, а у документов без активного ядра вместо нее отображается кнопка Delete. 2.9.7. Интерфейс документа Notebook Создав новый документ Notebook, вы увидите имя документа, панель меню, панель инструментов и пустую ячейку кода (рис. 2.21). ♦ Имя документа. Название, отображаемое вверху страницы рядом с логотипом Jupyter,— это имя файла ipynb. При нажатии на имя документа открывается диалоговое окно, позволяющее переименовать его. Таким образом, при пере­ именовании документа с «UntitledO» на «Первый документ» в браузере файл UntitledO.ipynb также переименуется на Первый документлрунЬ. Р'jupyter untitled Е® пк в ♦ VMW * «ль . .......... Имя документа к«п« insert см ♦ ♦ и Run И С » нмр сое. ПзНвЛЬ МвНЮ Панель инструментов Ячейка кода ш [ ); Рис. 2.21. Пустой документ Notebook ♦ Панель меню. В меню есть различные операции, которые можно использовать для работы с документом. ♦ Панель инструментов. На панель инструментов в виде иконок выведены самые распространенные операции над документом. ♦ Ячейка кода. Это тип ячейки по умолчанию. Подробнее о ячейках поговорим в следующем разделе.
Введение в Python | 83 2.9.8. Структура документа Notebook Документ состоит из последовательности ячеек. Ячейка представляет собой много­ строчное текстовое поле ввода, содержимое которого можно выполнить либо с по­ мощью комбинации клавиш <Shift>+<Enter>, либо путем нажатия кнопки Play на панели инструментов, либо с помощью пункта меню Cell | Run. Поведение ячейки при ее выполнении зависит от типа ячейки. Всего существуют три типа ячеек: ячейки кода, ячейки разметки Markdown и ячейки без формата. Каждая ячейка по умолчанию является ячейкой кода, но ее тип можно изменить с помощью выпа­ дающего списка на панели инструментов (изначально тип будет Code) или с по­ мощью горячих клавиш. Для получения дополнительной информации о том, что можно делать в документе Notebook, обратитесь к коллекции примеров. 2.9.9. Ячейки кода Ячейка кода позволяет редактировать и писать новый код с выделением синтаксиса цветом и заполнением табуляцией. Используемый вами язык программирования зависит от ядра, а ядро по умолчанию (IPython) запускает код Python. При выполнении ячейки содержащийся в ней код отправляется в ядро, связанное с данным документом. Результаты, полученные в процессе выполнения, отобража­ ются в документе как выходные данные ячейки. Вывод может быть не только тек­ стовым, но и представлен в других формах, включая рисунки Matplotlib и таблицы HTML (которые используются, например, в пакете анализа данных Pandas). Это и есть самые знаменитые возможности отображения IPython. 2.9.10. Ячейки Markdown Вы можете грамотно задокументировать вычислительный процесс, чередуя ячейки кода с описательным форматированным текстом. В IPython это достигается путем разметки текста с помощью языка Markdown. Соответствующие ячейки называются ячейками Markdown. Язык Markdown — это простой способ выполнить разметку текста и указать, какой текст нужно выделить курсивом, какой жирным шрифтом, где вставить список и т. д. Если вы хотите структурировать документ, вы можете использовать заголовки. За­ головки на языке Markdown обозначаются с помощью от I до 6 знаков решетки #, за которыми следует пробел и заголовок раздела. Заголовок Markdown преобразу­ ется в интерактивную ссылку на этот раздел документа. Он также используется в качестве подсказки при экспорте в другие форматы документов, например PDF. При выполнении ячейки Markdown разметка Markdown преобразуется в соответст­ вующий форматированный текст. Markdown также допускает форматирование с помощью HTML-кода. В ячейки Markdown можно напрямую включать математику, используя стандарт­ ную нотацию LaTeX: для внутристрочных выражений или для больших формул.
84 | Гпава 2 Когда выполняется ячейка Markdown, разметка LaTeX автоматически конвертиру­ ется в HTML с качественной типографикой. Это стало возможным благодаря MathJax, который поддерживает большое количество функций LaTeX. 2.9.11. Неформатированные ячейки В неформатированных ячейках можно напрямую писать выходные данные. Нефор­ матированные ячейки не анализируются документом и при передаче через nbconvert никак не преобразуются, и текст передается «как есть». Например, вы можете вве­ сти в неформатированную ячейку блок LaTeX, но отображаться как LaTeX он будет только после преобразования с помощью nbconvert. 2.9.12. Рабочий процесс Таким образом, стандартный рабочий процесс с таким документом очень похож на стандартный сеанс IPython, с той лишь разницей, что вы можете редактировать ячейки прямо на месте, пока не получите желаемые результаты, а не запускать отдельные сценарии с помощью магических команд. Как правило, работа над вычислительной задачей ведется по частям, т. е. вы рас­ пределяете связанные по смыслу идеи по ячейкам и продвигаетесь по этапам вперед по мере того, как предыдущие части начинают работать правильно. Такой способ намного удобнее для интерактивного исследования кода, чем разбиение вычислений на сценарии, которые должны выполняться вместе, особенно если вы­ полнение этих частей занимает много времени. Чтобы прервать вычисление, которое занимает слишком много времени, исполь­ зуйте команду меню Kernel | Interrupt или два раза нажмите клавишу <i>. Точно так же, чтобы перезапустить весь вычислительный процесс, используйте команду меню Kernel | Restart или два раза нажмите клавишу <0>. Документ можно скачать как файл формата ipynb или преобразовать в другой фор­ мат с помощью пункта меню File | Download as. 2.9.13. Горячие клавиши Все манипуляции над документом можно выполнять с помощью меню или мышью, но для наиболее распространенных действий также предусмотрены сочетания кла­ виш. Рекомендую запомнить наиболее важные из них: ♦ <Shift>+<Enter> — выполнить код в ячейке. Эта комбинация выполняет текущую ячейку, отображает полученный результат и переходит к следующей ячейке. Если команда <Shift>+<Enter> вызывается в последней ячейке, следом за ней создается новая ячейка. Это эквивалентно команде меню Cell | Run или нажатию кнопки Play на панели инструментов. ♦ <Esc> — командный режим. В командном режиме вы можете перемещаться по документу с помощью соче­ таний клавиш.
Введение в Python | 85 ♦ <Enter> — режим редактирования. В режиме редактирования вы можете редактировать текст в ячейках. ♦ <Н> (в командном режиме) — получение списка всех доступных сочетаний кла­ виш. 2.9.14. Построение графиков Одно из ключевых преимуществ документа Jupyter Notebook — возможность ото­ бражать графики, сгенерированные в результате выполнения ячеек кода. Ядро IPython специально спроектировано для бесшовной работы с библиотекой построе­ ния графиков Matplotlib, за счет которой и реализована эта функциональность. Ин­ теграция библиотеки построения графиков — это особенность ядра. 2.9.15. Совместимость с браузерами Jupyter Notebook поддерживает последние версии следующих браузеров: ♦ Chrome; ♦ Safari; ♦ Firefox; ♦ Edge. При использовании Safari с HTTPS и ненадежным сертификатом приложение не работает (а точнее, не работают веб-сокеты). 2.10. Что лучше использовать? Мы рассмотрели четыре способа использования Python и запуска кода Python. У каждого их них есть свои преимущества. Кроме того, большинство опытных про­ граммистов пользуются всеми этими способами, в зависимости от типа проекта, над которым ведется работа, и от наличия времени. Давайте кратко резюмируем сравнение всех способов. Командная строка— это простейший, но не самый элегантный способ запуска Python, как мы уже успели убедиться. Писать и запускать большое количество кода в командной строке неудобно, а отлаживать еще сложнее. Мы будем использовать командную строку лишь время от времени, для очень специфических целей, когда возникнет такая необходимость. IPython Qt консоль — это очень легкое приложение, во многом похожее на ко­ мандную строку, но с дополнительными функциями, которые можно реализовать только в графическом интерфейсе, такими как встраивание графиков, правильное многострочное редактирование с подсветкой синтаксиса, графические подсказки по вызовам и многое другое. Это приложение можно использовать как простой способ быстро проверить код или сценарий. Но все преимущества консоли также доступ­ ны в среде IDE, поэтому, когда под руками есть IDE, консоль выглядит устаревшей.
86 | Гпава 2 Spyder IDE — это приложение, используемое большинством программистов для написания, отладки и тестирования кода. В этой среде мы можем запускать код по­ строчно, а можем объединять фрагменты кода в ячейку и запускать всю ячейку вместе. Кроме того, здесь выводятся результаты и даже графики, отображаемые в соседнем окне. Именно в этом приложении вам захочется работать, когда вы чуть ближе познакомитесь с Python. Стоит отметить, что это не единственная IDE для Python. Есть и другие среды, но мы будем использовать именно эту, т. к. она входит в состав дистрибутива Anaconda по умолчанию и не имеет себе равных с точки зре­ ния функциональности. Jupyter Notebook— это интерактивная вычислительная веб-платформа. В ее до­ кументах сочетаются выполняемый код, математические уравнения, обычный текст, средства визуализации, интерактивные информационные панели и другие мультимедийные средства. Этот инструмент становится очень полезным, когда не­ обходимо опубликовать результаты анализа данных (а это нужно в большинстве случаев). Здесь вы можете писать код и документацию, создавать диаграммы и давать пояснения — и все в одном месте. Все перечисленные приложения работают на языке Python, и синтаксис языка у всех сред одинаковый, т. к. это просто интерфейсы для ядра Python. Решение о том, какой из них использовать, зависит от уровня подготовки пользователя и же­ лаемого результата. Я предпочитаю работать в Spyder IDE, а также иногда в Jupyter Notebook, если нужно предоставить полный анализ. Отмечу, что эта книга сама по себе полностью написана с использованием Jupyter Notebook. 2.11. Резюме В этой главе мы начали знакомство с волшебным миром Python. Python как язык программирования не имеет себе равных. Этот язык прост, универсален и в то же время очень ориентирован на конкретные задачи, такие как анализ данных и ма­ шинное обучение. В этой главе мы узнали, что такое Python, что он собой представляет и почему про­ граммисты его так любят. Мы также рассмотрели самый простой и эффективный способ установки Python с помощью дистрибутива Anaconda. Мы также познакомились с приложениями из Anaconda Navigator, такими как IPython-консоль, Spyder IDE и Jupyter Notebook. Без этих инструментов мы не сможем продолжать обучение, поэтому настоятельно рекомендую установить и освоить все инструменты, которые мы узнали в этой главе.
Введение в Python | 87 2.12. Упражнения 2.12.1. Ответьте на вопросы l. Python — это программное обеспечение с открытым исходным кодом. Это то же самое, что и бесплатное ПО? 2. У всех ли бесплатных программ открытый исходный код? А если нет, то в чем разница? 3. Python поддерживает динамическую типизацию. Что это такое? 4. Назовите 5 самых популярных языков программирования для специалистов по анализу данных. 5. В чем заключается преимущество Python по сравнению с языком С? 6. Python портативен. Что в этом контексте означает «портативность»? 7. В чем разница между «расширяемым» и «встраиваемым» языком? 8. В чем смысл IDE? Чем она отличается от командной строки? 9. Как открыть существующий документ Jupyter Notebook? Чем эта процедура от­ личается от открытия PDF-файла или текстового файла? 10. В чем разница между «ячейками разметки Markdown» и «ячейками кода» в Jupyter Notebook? Для чего они нужны? 2.12.2. Правда или ложь I. Язык программирования Python был назван в честь змеи питон. 2. Python — это высокоуровневый язык общего назначения. 3. Python компилируется и не интерпретируется. 4. В Python команда два + два вернет четыре. 5. Консоль IPython аналогична окну командной строки. 6. Графики, выводимые в документе Jupyter Notebook, отображаются внутри самого документа. 7. В комплекте с пакетом Anaconda идут браузеры Chrome и Firefox. 8. «Простое лучше, чем сложное» — это одна из философий Python. 9. Аббревиатура FLOSS означает «Free/Libre and Open Source Software». IO. Python поддерживает ТОЛЬКО объектно-ориентированное программирование.
88 | Гпава 2 2.12.3. Изучите самостоятельно 1. Попробуйте познакомиться с некоторыми основными командами терминала. 2. Установите пакет Anaconda согласно приведенным в этой главе инструкциям и запустите Spyder IDE. Ознакомьтесь с расположением элементов и их функ­ циями. 3. Запустите Jupyter Notebook. Ознакомьтесь с расположением элементов и их функциями. Обратите внимание на минималистичный дизайн и функции ячеек. 4. Попробуйте ввести одну и ту же строку кода или математическую операцию в IPython-консоль, Spyder IDE и Jupyter Notebook. Оцените разницу в использо­ вании этих инструментов и в отображении результатов. 5. Поищите информацию о волшебных командах в IPython и Jupyter Notebook.
3 Основы Python 3.1. Запуск Python Настало время изучить основы языка программирования Python. Необходимо, что­ бы вы проделывали самостоятельно все, что мы будем обсуждать. Для этого нужно открыть Spyder IDE или Jupyter Notebook. И поэтому сперва я расскажу вам об основах работы с этими программами, а затем вы сможете поэкспериментировать самостоятельно и узнать больше. Для создания этой книги я использовал Jupyter Notebook, и вы увидите сходство этой книги с оформлением документов. Jupyter Notebook — это хорошая отправная точка для начала обучения. Вы можете запускать свой код в ячейках кода и писать свой текст в ячейках Markdown. 3.1.1. Использование Spyder IDE Интегрированная среда разработки Spyder имеет свой графический интерфейс. Мы уже установили приложение Anaconda, в состав которого входит и Spyder. Поэтому сначала откройте Anaconda Navigator (см. рис. 2.14). Нажмите кнопку Launch под приложением Spyder. Откроется первое окно Spyder IDE со временным файлом (рис. 3.1). Для начала изучения нам понадобятся три основных компонента Spyder IDE (рис. 3.2). Вы узнаете больше о компонентах или функциях, когда начнете работу со средой. ♦ Редактор. Редактор Spyder во многих отношениях лучше простого текстового редактора. Помните, что это IDE, и, следовательно, ее функционал гораздо шире и включает в себя, например, нумерацию строк, выделение синтаксиса (ключе­ вые слова в синтаксисе подсвечиваются цветом), функции автозаполнения и многое другое. В этом многоязычном редакторе вы можете эффективно работать с функциями и классами, пользоваться инструментами анализа кода, автомати­ ческим завершением кода, горизонтальным/вертикальным разделением и пере­ ходом к определению объекта. ♦ Консоль IPython. Вам доступны возможности любого количества консолей IPython в сочетании с гибкостью графического интерфейса. Вы можете запус­ кать код по строкам, ячейкам или файлам, а также отображать графики прямо в строке.
| 90 Гпава 3 Рис. 3.1. Первый файл Spyder File Edit Search Sourfe gun Debug Cgnsoles Projects look yiew Help D fc :■= @ E E ■!» c :yjwrstoiabhrwhchhal 3 Обозреватель переменных Note ytxt can get beip st any object W pnssmti Ctsl«f m tprrtot Й, odhe. on Ihe fa<sx о» Ше Cunsate iteto can toss be shown autonsatoSy star writ-g a tofi parent®*» totrfto a* Wtect Wtfo» artvaw torn to Haw toSpyder? Rase ош to toftol 1 Редактор Python 3.7.6 (default, Jan 8 7020, 20:23:39) [MSC v.1916 64 bit (ATOM)] Гуре “copyright", “credits* or “license" for more information. IPython 7.12.0 -- An enhanced Interactive Python. 2 Консоль IPython iftothon сл-лЛе HBtory Рис. 3.2. Компоненты Spyder IDE ♦ Обозреватель переменных. Этот компонент позволяет взаимодействовать с переменными и изменять их на лету, строить гистограмму или временной ряд, редактировать датафреймы или массивы NumPy, сортировать коллекции, копаться во вложенных объектах и многое другое! Многие подробности станут понятнее по мере вашего прогресса в обучении, осо­ бенно если вы сами будете изучать новые вещи и экспериментировать в среде IDE.
| Основы Python 91 Если говорить просто, то в редакторе мы что-то пишем (в том числе код). Консоль IPython— это окно консоли, подобное командной строке, в котором выводятся результаты выполнения кода и которое можно использовать независимо от редак­ тора. В окне обозревателя переменных отображаются создаваемые объекты: новые переменные, классы, фреймы данных, диаграммы, графики и т. д. 3.1.2. Использование Jupyter Notebook Jupyter Notebook также входит в состав Anaconda, поэтому снова откройте окно Anaconda Navigator. Нажмите кнопку Launch под приложением Jupyter Notebook. Стартовое окно Jupyter Notebook откроется в браузере, который установлен по умолчанию (рис. 3.3). Home Реде - Select or create а ■ С X О + X Ф Iocalhost8889/tree jupyter Files Running Quit Clusters Logout Nbextensions Select items to perform actions on them Notebook □ 0 Name □ Cj debug log b | Create a new notebook with Python 3 Q D Downloads О Python 3 Text File Folder OneDrive Terminal □ C3 DscSignerAppLogs 13 hours ago О C3 Desktop О C3 PYTHON_BOOK_NILABH □ C3 Documents □ C3 build 2 daysago 8 days ago 8 days ago О C3(fot 8 days ago О D Currency Converter NUabh spec 8 days ago 924 В О & SESSION 38 PROJECT S IMPLEMENTATION - IMAGE CLASSIFICATION, ipynb a month ago 135 kB О ® Example ipynb a month ago 842 kB Рис. 3.3. Стартовая страница Jupyter Notebook Папки, которые вы увидите, могут отличаться от моих, т. к. по умолчанию Jupyter Notebook открывается на папке вашего пользователя. На рис. 3.3 видно, что в моей личной папке уже есть несколько файлов ipynb. Чтобы открыть любой из них, дос­ таточно щелкнуть по нему мышью. Но вы запустили программу впервые, вам нужно создать первый документ. Чтобы создать документ Notebook, нажмите на кнопку New в правом верхнем углу и выберите пункт меню Python 3 (рис. 3.3). Откроется новая веб-страница с одной пустой ячейкой и без имени (с именем Untitled в строке заголовка). Теперь вы можете добавлять в документ любое количество ячеек, удалять их, изме­ нять порядок отображения и многое другое. На рис. 3.4 показана страница моего
92 | Гпава 3 документа Jupyter Notebook, открытого на этой главе, и подписаны различные эле­ менты окна. По мере работы с этой программой вы узнаете больше о ее возмож­ ностях. Рис. 3.4. Компоненты Jupyter Notebook Чтобы запустить строку кода, просто введите ее в ячейку, оставьте тип ячейки Code (который задан по умолчанию) и используйте любой из способов запуска: ♦ с помощью мыши — откройте пункт меню Cell. Используйте любой из вариан­ тов запуска, какой вам подходит; ♦ с помощью клавиатуры — к пунктам меню Cell можно обращаться с помощью горячих клавиш. Вот три наиболее часто используемых сочетания клавиш для запуска кода: • <Shift>+<Enter> — запустить ячейку и перейти к следующей; • <Ctrl>+<Enter> — запустить выбранные ячейки; • <Alt>+<Enter> — запустить ячейку и вставить новую ниже. 3.2. Начнем с «Hello World!» Давайте продолжим традицию изучать компьютерное программирование прове­ ренным поколениями методом — с помощью «Hello World!». Мы уже видели такую программу, когда пробовали писать первый код. Давайте напишем то же самое еще раз в Spyder IDE или в Jupyter Notebook. In [1]: print("Hello World!") |Hello World! Команда пишется в окне редактора Spyder IDE, а затем нужно открыть меню Run. Используйте пункт меню Run selection or current line, чтобы запустить эту мини-
Основы Python | 93 программу. Результат работы появится в окне консоли. Горячая клавиша для запус­ ка кода — <F9>. Если вы используете Jupyter Notebook, то для запуска кода используйте горячие клавиши или мышь, как было рассказано в предыдущем разделе. Обычно слово «print» в программировании не означает, что результат будет на­ печатан на вашем принтере. Имеется в виду отображение результата команды на экране. То же самое и с функцией print (). 3.3. Использование Python как калькулятора1 Давайте попробуем выполнить несколько простых команд Python. Запустите Spyder IDE и введите приведенные ниже команды в редакторе. Сравните ваш вывод с моим выводом здесь и посмотрите, получите ли вы такие же результаты. 3.3.1. Числа Интерпретатор Python можно использовать как простой калькулятор: мы вводим в него выражение, а он возвращает значение. Синтаксис выражений прост: арифме­ тические операторы +, -, * и / работают так же, как в любой компьютерной про­ грамме, которую вы могли использовать, например, в цифровом калькуляторе или электронной таблице Excel; круглые скобки о, как обычно, могут использоваться для группировки. Например: In [2] : |0ut[2]: In [3] : |Out[3]: In [4]: [Out[4]: In [5]: |Out[5]: 2 + 2 4 50 - 5 * 6 20 (50 - 5 * 6) /4 5.0 8/5 # результат деления всегда с плавающей точкой 1.6 Целые числа (например, 2, 4, 20) имеют тип int, а числа с дробной частью (напри­ мер, 5.0, 1.6) имеют тип float. О числовых типах мы поговорим позднее. Оператор деления / всегда возвращает float. Чтобы выполнить деление нацело и получить целочисленный результат (отбрасив дробную часть), вы можете исполь­ зовать оператор //, а для вычисления остатка — оператор %. In [6]: |Out[6]: 1 17/3 # обычное деление с плавающей точкой 5.666666666666667 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
94 | Гпава 3 In [7]: |Out[7]: 17 И 3 1 5 In [8]: 17 % 3 Out[8]: 2 In [9]: 5*3 + 2 |Out[9]: # целочисленное деление # остаток от деления 1 # проверка: результат * делитель + остаток 1 17 Для вычисления степени можно использовать оператор **. In [10] : 5 ** 2 Out[10] : 25 In [11]: 2 ** 7 Out[11]: 128 # 5 в квадрате 1 # 2 в степени 7 1 Знак равенства = используется для присвоения значения переменной. После при­ своения результат не отображается: In [12]: width = 20 height =5*9 # обратите внимание, что этот код ничего не возвращает 3.3.2. Строки Помимо чисел Python может также работать со строками, которые можно задавать несколькими способами. Они могут быть заключены в одинарные '...' или двой­ ные кавычки "...". Для экранирования кавычек используется символ \: In [13]: 'python strings' |Out[13] : 'python strings' In [14] : 'doesn\'t' Out[14] : "doesn't" In [15]: "doesn't" Out[15]: "doesn't" # одиночные кавычки # используйте \ для экранирования кавычки... □ # ...или используйте двойные кавычки В интерактивном интерпретаторе строка вывода заключается в кавычки, а специ­ альные символы экранированы обратной косой чертой. На вид такая строка отлича­ ется от ввода (сами кавычки могут быть другими), но эти две строки все равно эквивалентны. Строка заключается в двойные кавычки, если содержит внутри себя одинарные кавычки и не содержит двойных кавычек, в противном случае строка заключается в одинарные кавычки. Функция print о позволяет получить более читаемый вывод, опустить кавычки и вывести экранированные и специальные символы:
Основы Python In [16]: |Out[16]: In [17]: ”'Isn\'t," they said.' "4sn\'t," they said.' | 95 | print('"Isn\'t," they said.') ["Isn't," they said. Если вы не хотите, чтобы управляющие символы (такие как \n, \t) интерпретирова­ лись как специальные, вы можете использовать необработанные строки, добавив букву г перед первой кавычкой: In [18]: print('C:\some\name') # здесь \п - переход на новую строку! print(r'C:\some\name') # г перед открывающей кавычкой C:\some ате In [19]: |С:\some\name 3.3.2.1. Конкатенация и повторение Строки можно объединять (склеивать) с помощью оператора + и повторять с по­ мощью оператора *. Запомнить это просто. Оператор + складывает, а оператор * умножает. In [20]: |Out[20]: 'а' + 'Ь' 'ab' In [21]: 't' * 5 |Out[21]: 'ttttt' In [22]: |Out[22]: 'no' * 3 + 'dip' 'nononodip' Два или более строковых литерала (заключенных в кавычки строки), расположен­ ных рядом друг с другом, автоматически объединяются. In [23]: |Out[23]: 'nil' 'abh' 'nilabh' Это особенно удобно, если требуется разделить длинные строки. In [24]: text = ('Put several strings within parentheses -' '- to have them joined together.') text |Out[24]: 'Put several strings within parentheses — to have them joined together.' 3.3.2.2. Индексирование Строки можно индексировать (обращаться к элементам строки по индексу), при этом первый символ имеет индекс 0. Отдельного типа для данных символов не существует, т. к. символ — это просто строка длиной в один символ. |
96 | Гпава 3 In [25]: word = 'Python' word[0] |Out[25]: In [26]: |Out[26]: # символ в позиции О 'Р' word[5] # символ в позиции 5 'n' Для отрицательных индексов отсчет ведется справа: In [27]: |Out[27]: word[-4] 't' Обратите внимание: поскольку -0 равняется 0, то отрицательные индексы начина­ ются с -1. 3.3.2.3. Срезы Помимо индексирования строк также поддерживаются срезы. Если индексирование используется для извлечения отдельных символов, то срез возвращает подстроку. In [28]: |Out[28]: In [29]: |Out[29]: word[0:2] # с позиции 0 (включительно) ло 2 (не включая его) 'Ру' word[2:5] # с позиции 2 (включительно) до 5 (не включая его) 'tho' Обратите внимание, что начальный индекс всегда включается, а конечный всегда исключается. Это гарантирует, что s [: i] + s [i: ] всегда равно s. In [30]: |Out[30]: In [31]: |Out[31]: word[:2] + word[2:] 'Python' word[:4] + word[4:] 'Python' У срезов есть полезные значения по умолчанию для индексов. Опущенный первый индекс по умолчанию равен нулю, опущенный второй индекс по умолчанию равен длине строки. Чтобы запомнить, как работают срезы, можно представить индексы как разде­ лители между символами (рис. 3.5), при этом левый край первого символа имеет
Основы Python | 97 номер 0. Тогда правый край последнего символа строки из п символов имеет ин­ декс п. В первой строке чисел указано положение индексов от 0 до 6, во второй строке даны соответствующие отрицательные индексы. Срез строки от i до j состоит из всех символов между индексами i и j соответственно. +—+—+—+—+—+—+ |P|y|t|h|o|n| +---- +--- +--- +--- +--- +--- + 0 1 2 3 4 -6 -5 -4 -3 -2 5 6 -1 Рис. 3.5. Срезы слова Python Строки Python нельзя изменить— они неизменяемы. Следовательно, присвоить новое значение символу по определенному индексу нельзя. Если вы попытаетесь это сделать, получите ошибку: In [32]: word[2] = Traceback (most recent call last) TypeError <ipython-input-32-27e525a0336b> in <module> --- > 1 word[2] = TypeError: 'str' object does not support item assignment Если вам нужна новая строка, нужно ее создать. In [33]: |Out[33]: In [34]: # встроенная функция 1еп() возвращает длину строки len(word) 6 s = 'supercalifragilisticexpialidocious' len(s) |Out[34]: 34 3.4. Синтаксис кода Python 3.4.1. Выражения Строки, написанные в исходном коде для выполнения, называются выражениями (рис. 3.6), которые могут состоять из операторов разных типов, таких как оператор присваивания, условный оператор, оператор цикла и т. д. Все они нужны для того, чтобы пользователь мог получить нужный результат. Например, п = 20 — это вы­ ражение с оператором присваивания. Выражения могут быть однострочными или многострочными. Многострочные вы­ ражения можно переносить на другие строки с помощью круглых скобок (), фи-
98 | Гпава 3 гурных скобок {}, квадратных скобок [], обратной косой черты (\). Если програм­ мисту нужно выполнить длинные вычисления, а выражение не помещается в одну строку, эти символы помогут выйти из ситуации. Чтобы лучше понять приведенные выше понятия, рассмотрим примеры. # перенос выражения на новую строку с использованием \ з = 1 + 2 + 3 + \ 4 + 5 + 6 + \ 7 + 8 + 9 # перенос выражения на новую строку с использованием () п=(1 *2*3 + 7 + 8 + 9) # перенос выражения на новую строку с использованием [] footballer = ['MESSI', 'NEYMAR', 'SUAREZ'] # перенос выражения на новую строку с использованием (} х={1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9} Выражения — это строительные блоки любой программы. Это те самые действия, которые ваша программа должна выполнить. Нет выражений — нет и программы. Каждое выражение может состоять из ключевых слов, других выражений и опера­ торов. 3.4.1.1. Окончание выражений В Python конец строки означает конец выражения. Но мы также рассмотрели, как написать выражение в нескольких строках.
Основы Python | 99 Можно также завершить выражение с помощью точки с запятой (;). Иногда за счет этого можно размещать нескольких выражений в одной строке, например: flag = 2; ropes = 3; pole = 4 3.4.2. Переменные и присваивание значений Одна из самых мощных функциональностей любого языка программирования — это возможность работать с переменными. Переменная — это некоторое имя, свя­ занное со значением. Обратите внимание, что переменная лишь ссылается на зна­ чение, которое ей присвоено, но не тождественна ему. Когда переменной присваи­ вается другое значение, старое присвоение сразу становится недействительным. Оператор присваивания позволяет автоматически создавать новые переменные и присваивать им значения: In [35]: # переменной а присваиваем значение 45 а = 45 # и выводим значение переменной на экран print (а) I45 In [36]: # присваиваем той же переменной другое значение а = 3 + 2 # и снова выводим print(а) 5 Нетрудно видеть, что переменная а принимает новое значение, как только мы его присвоили. 3.4.3. Имена переменных и ключевые слова Для переменных следует выбирать имена со смыслом, которые что-то говорят о хранимых данных. Например, при работе с данными о продажах магазина в вы­ ходные подойдет имя переменной Sales_weekend. Это не строгое правило, но его соблюдение очень важно для обеспечения читабельности кода. И поскольку пере­ менная может использоваться в коде несколько раз, такое именование поможет вам как программисту ориентироваться в своем же коде. Имена переменных могут быть любой длины и содержать как буквы, так и числа. Писать имена можно в верхнем или нижнем регистре, но одно и то же имя с раз­ ными регистрами — это будут разные переменные, т. к. Python чувствителен к ре­ гистру. Существует еще несколько правил именования переменных. ♦ Имя должно начинаться с буквы (не с цифры). ♦ В имени может присутствовать символ подчеркивания (_). Он используется для соединения слов в длинном имени переменной, т. к. пробелы использовать нельзя.
100 | Гпава 3 ♦ Нельзя использовать в качестве имен переменных ключевые слова Python: and def exec if not return assert del finally import or try break elif for in pass while class else from is print yield continue except global lambda raise Сохраните себе этот список для справки. Назначив переменной недопустимое имя, вы получите синтаксическую ошибку. Давайте потренируемся. Ниже приведен список из 10 имен. Определите, какие из них нельзя использовать в Python: 2nd_wife man_vs_wild "national geographic" pythonl23 class global data_science tomorrow sudhir22 Sundar_ban Проверьте свои догадки, присвоив этим именам любые значения, и запустите код. В зависимости от результата, вы получите или не получите синтаксическую ошибку. 3.4.4. Выполнение выражений Выражение — это совокупность значений, переменных и операторов. Когда вы вводите в командной строке выражение, интерпретатор вычисляет его и выводит результат. In [37] : |Out[37]: 2 + 3 5 Выражения могут содержать значения, переменные и операторы, но не обязательно все их сразу. Само по себе значение тоже считается выражением, как и отдельно взятая переменная. In [38]: 15 |Out[38]: 15 In [39]: |Out[39]: а 5 Вычислить выражение — это не то же самое, что вывести его значение на экран. Покажем это на примере строки. In [40]: 'Hello World!' |Out[4Q]: 'Hello World!' In [41]: print('Hello World!') | Hello World! Когда интерпретатор Python выводит значение выражения, он использует тот же формат, который вы использовали бы для ввода значения. Для строк это означает, что будут выведены кавычки. Но если вы используете функцию print о, Python отображает содержимое строки без кавычек.
Основы Python | 101 3.5. Первые шаги в программировании' Конечно, мы можем использовать Python для более сложных задач, чем сложение двух чисел. Например, можно вычислить начало ряда Фибоначчи следующим об­ разом: In [42] : # ряд Фибоначчи # сумма двух элементов — это следующий элемент ряда а = О Ь = 1 while а < 10: print(а) a, b = b, а + Ь О 1 1 2 3 5 8 Давайте поэкспериментируем с этим простым кодом. Для начала изменим способ присвоения переменных а и ь. Значения будут такими же, но число строк сократит­ ся. Также изменим условие в цикле, чтобы показать, как оно влияет на результат. In [43]: # тот же ряд Фибоначчи а, b = 0, 1 while а < 15: print(а) а, b = b, а + Ь 0 1 1 2 3 5 8 13 Вы заметили, что этот код работает так же, как и первый вариант? Кроме того, верхний предел для значения а теперь равен 15, и, следовательно, выводится еще одно число— 13. В этом примере появилось сразу несколько новых выражений. 1. В первой строке используется множественное присваивание: переменные а и ь одновременно получают значения о и 1. В последней строке кода это использу1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
102 | Гпава 3 ется снова, причем здесь важно, что перед таким присваиванием всегда сначала вычисляется правая часть. Выражения в правой части вычисляются слева на­ право. 2. Цикл while выполняется до тех пор, пока условие остается истинным (в первом варианте это было а < 10, которое мы позже изменили на а < 15). В Python ис­ тинным является любое ненулевое целочисленное значение, ноль считается ложным. Условие также может быть строкой или списком и вообще любой по­ следовательностью. При этом все, что имеет ненулевую длину, считается истин­ ным, а пустые последовательности — ложными. Условие, использованное в на­ шем примере, представляет собой простое сравнение. Стандартные операторы сравнения записываются привычным образом: < (меньше), > (больше), == (равно), <= (меньше или равно), >= (больше или равно) и ! = (не равно). 3. Тело цикла записано с отступом. Отступы — это способ группировки выраже­ ний в Python. В интерактивном режиме интерпретатора для задания отступа нужно использовать табуляцию или пробелы. На практике код бывает гораздо более сложным, и у всех специализированных текстовых редакторов есть функ­ ция автоматического отступа. Когда составное выражение вводится в интерак­ тивном режиме, за ним должна следовать пустая строка, указывающая на завер­ шение (поскольку синтаксический анализатор не может угадать, когда блок кода закончился). Обратите внимание, что у всех строк в блоке должен быть одина­ ковый отступ. 4. Функция print о выводит значение переданного аргумента на экран. Ее работа отличается от простого написания выражения в строке (как мы делали ранее), т. к. эта функция по-другому обрабатывает несколько аргументов, числа с пла­ вающей запятой и строки. Строки выводятся без кавычек, а между аргументами вставляется пробел, что позволяет красиво форматировать результаты: In [44]: i = 256*256 print('The value of i is', i) |The value of i is 65536 3.5.1. Подробнее о функции print() Рассмотрим пару важных понятий на примере функции print(). Поскольку вы будете часто использовать ее, это будет полезно само по себе. Мы уже видели, что функция print () выводит любой аргумент, который мы указы­ ваем в скобках. Это еще не все. Давайте взглянем на функцию print о поближе. Фактический синтаксис функции print () выглядит так: print(‘objects, sep=' ', end='\n', file=sys.stdout, flush=False) На примере этого синтаксиса рассмотрим еще две важные концепции программи­ рования на Python: ♦ Аргументы (иногда обозначаемые словом args); ♦ Именованные аргументы (иногда обозначаемые словом kwargs).
Основы Python | 103 Как и раньше, мы разберемся с этими сложными понятиями самым простым спо­ собом. Это означает, что по ходу рассуждения я сделаю небольшие упущения, но суть постараюсь передать. Аргументы — это все, что мы передаем в функцию. Например, в функцию print о мы передавали строку или переменную — это и есть аргументы. Если при опреде­ лении функции вы хотите передавать ей больше одной переменной, но еще не знае­ те точно, сколько аргументов у вас будет, можно указать специальный синтаксис *args. Символ * здесь означает, что мы можем передать функции любое количество переменных, а слово args — это своего рода стандартное соглашение, которое ис­ пользуется для лучшей читаемости кода. Можно использовать и любое другое сло­ во, если оно будет достаточно значимым. Как видите, в синтаксисе функции print () вместо *args используется слово ‘objects. Теперь вы знаете, что это означает, и в функцию print!) можно передать несколько аргументов (переменных, строк, классов или любых других объектов). Именованные аргументы — это аргументы, для которых при передаче в функцию указывается не только значение, но и имя. И здесь давайте остановимся и рассмот­ рим подробнее это понятие на пример синтаксиса функции print!). Вы заметили в заголовке функции слова sep=, end=, file= и fiush=? Это именованные аргументы, у них есть имя, а справа от символа = указано присвоенное им значение. Значения, указанные в определении функции, являются значениями по умолчанию. То есть если вы не назначите такому аргументу другое значение, будет передано значение по умолчанию, и синтаксических ошибок не возникнет. Теперь, разобравшись с аргументами и именованными аргументами, давайте разбе­ ремся, что означает синтаксис print () и как с ним работать. Еще раз: print(*objects, sep=' end='\n', file=sys.stdout, flush=False) Параметры функции print (): ♦ ‘objects — любое количество любых объектов. Перед выводом все объекты со­ бираются в строку; ♦ sep=' ' (необязательный)— задает разделитель объектов, если их несколько. Значение по умолчанию — символ пробела, указанный как ' '; ♦ end='\n' (необязательный)— определяет, что вывести в конце строки. Значение по умолчанию — символ переноса строки '\п'; ♦ file=sys. stdout (необязательный) — объект с методом write (string). Если этот параметр не указан, будет использоваться sys. stdout по умолчанию, что означает вывод результатов на экран; ♦ fiush=False (необязательный) — логическое значение, указывающее, будет ли вывод очищен (True) или буферизован (False). По умолчанию имеет значение False. А теперь потренируемся. Обратите внимание на изменения в следующих строках кода. Для лучшего понимания мы будем использовать тот же простой код для ряда Фибоначчи, который мы написали ранее.
104 | In [45]: Гпава 3 # тот же ряд Фибоначчи а, b = 0, 1 while а < 15: print(a, end=', а, b = b, а + Ь 10, 1, 1, 2, 3, 5, 8, 13, ') ~ Теперь попробуйте самостоятельно позадавать разные значения именованным аргументам функции print () и посмотреть, что изменится. 3.5.2. Форматированный вывод И в продолжение темы, я хочу вас познакомить с удобным способом вывода результатов на экран. Подробнее мы рассмотрим его позднее, когда дойдем до форматирования строк. Но сейчас ничто не мешает вам его попробовать. In [46]: а = 5 Ь = 6 ab = 5 * 6 print("when {} is multiplied by {}, the result is {[".format(a, b, ab)) |when 5 is multiplied by 6, the result is 30 In [47]: # вариант co строками name = "Nilabh" lastname = "Nishchhal" place = "Mumbai" print("{} {} lives in {}".format(name, lastname, place)) |Nilabh Nishchhal lives in Mumbai В двух приведенных примерах если вы измените значения переменных, то выход­ ные данные тоже изменятся вместе с ними. Этот инструмент будет весьма полезен вам в следующих главах. 3.5.3. Простейшая геометрия и print() Мы рассмотрели использование функции print о и ее синтаксис. Теперь мне хочется показать вам небольшой трюк. Нарисуем треугольник, используя только базовый код. In [48]: print)" /I") print (" / I") print(" print(" print(" / I I I") I") |") print ("/I")
Основы Python | 105 Это простейший способ вывода фигур. В следующих главах, когда мы узнаем о циклах и условных операторах, мы нарисуем несколько других фигур, а заодно узнаем, как работают циклы. 3.6. Поиск ошибок' К поиску ошибок приходится прибегать в случаях, когда наш код не выдает желае­ мого результата или вообще ничего не выводит. Если код не выдает результат, ве­ роятно, где-то возникла ошибка. Сообщения об ошибке в Python пишутся довольно подробно и позволяют точно понять, в чем заключается и где находится ошибка. У начинающих программистов ошибки появляются регулярно. У многих новичков есть привычка тут же закрывать сообщение об ошибке, не читая, а затем присталь­ но смотреть на код в ожидании того, что проблема каким-то образом разрешится сама. Построчный просмотр кода, наверное, рано или поздно поможет найти про­ блему, но сообщения об ошибках позволяют сразу понять, куда надо смотреть. Рассмотрим три основных типа ошибок, которые возникают чаще всего. ♦ Синтаксическая ошибка — проблемы с языковыми конструкциями. ♦ Ошибка времени выполнения — проблемы с выполнением кода. ♦ Семантическая ошибка — неожиданный результат. 3. 6.1. Синтаксические ошибки Эти ошибки обычно вызваны опечатками, но в более широком смысле наличие такой ошибки означает, что возникла проблема со структурой вашей программы. Ошибка возникает, когда вы пишете код, не соблюдая синтаксис Python. Приведен­ ное ниже сообщение об ошибке Python указывает на ошибку в синтаксисе. In [49]: # отсутствует закрывающая кавычка print("Hello World!) File "<ipython-input-49-9d0e3bd45f27>", line 3 print("Hello World!) A SyntaxError: EOL while scanning string literal В сообщении об ошибке сказано, что со строковым литералом что-то не так. Кроме того, ошибка указывает на место, где была найдена проблема. In [50]: # пропущен оператор между 4 и 5 х = 3+ 4 5 х File "<ipython-input-50-44afb4dc20cc>", line 3 х = 3+ 4 5 Л SyntaxError: invalid syntax 1 Magee, 2019 (https://www.cs.bu.edu/courses/csl08/guides/debug.html) [11].
106 | Гпава 3 И снова в тексте ошибки указан тип ошибки и место, где найден неверный син­ таксис. Пока мы рассматриваем только однострочные примеры, но в более длинных про­ граммах вам, возможно, придется просмотреть весь файл, чтобы найти проблему. Лучшее решение, чтобы избежать длительного поиска ошибок, — это запускать программу через каждые несколько строк кода. Столкнувшись с ошибкой, вам нужно будет проверить лишь самые последние изменения, и с большой долей веро­ ятности ошибка будет именно в них. 3. 6.2. Ошибки времени выполнения Ошибки времени выполнения возникают во время работы программы. Поскольку Python является интерпретируемым языком, такие ошибки возникают лишь в тот момент, когда выполнение программы доходит до ошибочной строки. Частые причины таких ошибок следующие: ♦ неверно введенное имя переменной или функции; ♦ использование переменной до ее определения; ♦ имя должно было быть заключено в кавычки; ♦ деление на ноль. Ошибка времени выполнения возникает, когда Python понимает саму команду, но при ее выполнении сталкивается с проблемами. Поэтому эта ошибка и называется «времени выполнения», поскольку возникает только после запуска программы. In [51]: 5/0 ZeroDivisionError Traceback (most recent call last) Cipython-input-51-0106664d39e8> in <module> --- > 1 5/0 ZeroDivisionError: division by zero Здесь синтаксис кода правильный, но интерпретатор не умеет делить на 0. Следо­ вательно, программа запускается, но выдает ошибку. Это ошибка времени выпол­ нения. 3. 6.3. Семантические ошибки Семантические или логические ошибки — это проблемы с самим построением вашей программы. Обычно такие проблемы не вызывают сообщений об ошибках, но поведение программы оказывается неверным. Ошибки такого типа сложнее всего отследить. Эти ошибки часто бывают вызваны случайным использованием неверных пере­ менных либо просто неправильными вычислениями.
Основы Python In [52]: | 107 # мы хотим вывести "Hello Nilabh" name = "Nilabh" print("Hello name") |Hello name Вы можете заметить, что в этом примере сообщение об ошибке отсутствует. Но и желаемого результата мы не получили. Причина в том, что мы думали, что переда­ ем переменную name и Python выведет ее значение. A Python воспользовался стро­ ковым синтаксисом и понял все буквально. Семантические ошибки — самые сложные в устранении. 3. 6.4. Когда никакие средства не помогают... Вы можете столкнуться с ситуациями, когда найти ошибку, которая приводит к серьезному сбою вашей программы, не удается. В этом случае можно предпри­ нять несколько шагов: 1. Поиск в Интернете. Лучшее место для поиска ответов — это сайт stackoverflow.com 2. Избегать таких случаев. Всегда стоит сначала писать несколько строк кода, а затем выполнять программу. Затем добавлять еще несколько строк кода и снова запускать. Столкнувшись с проблемой, вам достаточно будет просмотреть несколько последних изменений, которые вы внесли, и проблема найдется быст­ рее. 3. Промежуточные версии. Следует сохранять промежуточный прогресс в разра­ ботке программы каждый раз, когда вы начинаете писать новую часть. Если вы достигли определенного этапа, сделайте резервную копию. Для этого достаточ­ но выбрать пункт меню Save as и назвать свой файл filename!.ру, затем (ИепашеЗ.ру и т. д. Если вы работаете с filename7.py и столкнулись с нерешае­ мой проблемой, можно просто вернуться к filename6.py. По окончании работы можно просто убрать все старые файлы в архив и переименовать окончательный файл по своему усмотрению. 4. Комментарии. Вы можете попытаться закомментировать проблемный участок кода, чтобы посмотреть, сохранится ли проблема. Вы можете использовать воз­ можности среды IDE, чтобы поместить символ комментария перед всеми стро­ ками выделенного фрагмента кода. Попробуйте изолировать разные участки кода, чтобы сузить область поиска проблемы. 5. Все сначала. Когда ничего не помогает, вы можете начать писать заново, с но­ вого пустого файла. Затем скопируйте и вставьте небольшие фрагменты кода из старого файла по одному. Каждый раз, добавляя новый раздел, запускайте свою программу и проверяйте, не появилась ли проблема.
108 | Глава 3 3.7. Резюме В этой главе мы сперва познакомились со Spyder IDE и Jupyter Notebook. Затем мы начали работу с Python и научились использовать его в качестве калькулятора. Мы также проделали несколько манипуляций со строками. Затем мы обратились к ба­ зовой структуре кода Python и узнали, что такое выражения, операторы и перемен­ ные. Мы также написали первую многострочную программу и изучили несколько принципов написания кода на Python, таких как множественное присваивание, от­ ступы, цикл и вывод результата. Затем мы рассмотрели, как работает функция print (), и ее синтаксис помог нам разобраться еще с двумя понятиями, такими как аргументы и именованные аргументы. Последней темой, которую мы рассмотрели, был поиск ошибок, и это тоже невероятно важно. Вооружившись базовыми зна­ ниями о Python, давайте приступим к изучению теоретических основ языка Python. 3.8. Упражнения 3.8.1. Ответьте на вопросы 1. В чем преимущества редактора Spyder IDE по сравнению с простым текстовым редактором? 2. Как в Python пишутся операторы сложения, вычитания, умножения и деления? 3. В чем разница между операторами * и **? Что они означают в Python? 4. Что такое выражения в Python? Зачем они нужны? 5. Что такое переменная? Как присвоить переменной какое-либо значение? 6. Можно ли в Python дать переменной имя import? 7. В Python имена math, нуйте свой ответ. math. Math эквивалентны Обоснуйте ответ. Так ли это на самом деле? Обос­ 8. Каким образом можно группировать выражения в Python? 9. В чем разница между синтаксической ошибкой и семантической ошибкой? 10. Каково значение по умолчанию именованных аргументов sep и end в синтаксисе функции print () ? 3.8.2. Правда или ложь 1. Простое деление четного числа на 2 вернет объект типа int (целое число). 2. Положительный индекс строки начинается с 0, а отрицательный индекс начина­ ется с -1. 3. Строки Python можно изменять, или, другими словами, они изменяемы. 4. Dream Team — это допустимое имя переменной в Python. 5. В Python можно дать переменной имя lambda.
Основы Python | 109 6. Выражения в Python завершаются точкой (.). 7. Выражения а = 25 и а == 25 в Python эквивалентны. 8. Вывод выражения с использованием функции print () — это не то же самое, что вычисление этого выражения. 9. Семантические ошибки являются подвидом синтаксических ошибок. 10. Деление на ноль вызывает ошибку времени выполнения. 3.8.3. Практические задания 1. Напишите программу, в которой бы соединялись ваши имя и фамилия. Между ними должен быть пробел. 2. Прямоугольник имеет длину 1 (англ, буква /) и высоту h. Напишите код для вы­ числения площади прямоугольника с высотой 8 и длиной 23. В коде должно быть присвоение значений переменным 1 и h, чтобы один и тот же код можно было использовать повторно. Для вычисления площади прямоугольника нужно его длину умножить на высоту. 3. Чему равен квадрат числа 32 и куб числа 27? Напишите оператор, который от­ ветит на этот вопрос. 4. Напишите приведенное ниже уравнение на Python. Присвойте числовые значе­ ния переменным и вычислите результат. (а + Z>)2 = а2 + b2 + 2аЬ 5. Найдите длину своего имени, написав однострочный код на Python. 6. Нарисуйте прямоугольник, используя функцию print (). 7. Нарисуйте букву «Р» с помощью простейшей геометрии и функции print (). 8. Создайте переменную Name и присвойте ей свое имя. Переменной Аде присвойте свой возраст. Затем напишите оператор print(), который выведет текст «меня зовут Name, а мой возраст - Аде», с подставленными значениями ваших перемен­ ных. Значения Name и Аде должны быть строкой и числом соответственно. 9. Исправьте синтаксическую ошибку в следующих строках кода: words = [cat, window, defenestrate] for w in words: print(w, len(w)) 10. Исправьте синтаксическую ошибку в следующих строках кода: а, Ь = 0, 1 while а < 15: print(a, end=',') а, Ь = Ь, а + Ь
110 | Гпава 3 3.8.4. Изучите самостоятельно 1. Запишите свое имя на бумаге. Под именем напишите положительные и отрица­ тельные индексы строки. 2. Постепенно начните в качестве калькулятора использовать Spyder IDE или Jupyter Notebook. 3. Зайдите на сайт stackoverflow.com. Он станет вашим лучшим помощником, когда вы начнете учиться на своих ошибках.
4 Объекты и операторы в Python В этой главе основное внимание будет уделено базовой семантике языка Python. В отличие от синтаксиса, который мы рассмотрели в предыдущей главе, в семанти­ ку языка входит не написание, а значение операторов. В этой главе рассматривается семантика переменных и объектов. Они предназначе­ ны для хранения, обращения и работы с данными в скрипте Python. 4.1. Переменные Переменные в Python — это просто указатели. Сами по себе они не имеют значе­ ний, а просто указывают на объект, который им присвоен. Технически перемен­ ные — это просто области в памяти вашего компьютера, в которых хранится неко­ торая информация. Значения переменных, как следует из самого слова «перемен­ ная», могут меняться. То есть вы можете хранить что угодно в переменной. В предыдущей главе мы уже работали с переменными. Теперь давайте копнем глубже и рассмотрим следующие примеры. In [1]: х = 38 у = "emailid@python.coin" In [2]: print(х) print(у) 38 emailid@python.com Заметили разницу между внешним видом этих двух переменных при выводе? Переменная х вывелась так, как и была присвоена, а значение у напечатано без кавычек. Дело в том, что Python автоматически определяет, какой тип значения вы присваи­ ваете переменной. Самим вам не нужно определять или указывать типы пере­ менных. Достаточно придумать имя переменной и присвоить ей значение, a Python автоматически определит ее тип. In [3]: print(type(х)) print(type(у))
112 | Гпава 4 <class 'int'> Cclass 'str'> 4.1.1. Оператор присваивания Когда мы вводим переменную вида х = 38, то в этой записи х — это имя перемен­ ной, (=) — это оператор присваивания, а 38 — это присвоенное значение. Здесь, в отличие от арифметики, знак (=) не означает «равно». Он означает «при­ своить». В Python «равно» записывается как ==. Мы увидим это позже, когда будем изучать операторы сравнения. 4.1.2. Имена переменных В предыдущей главе мы уже касались вопроса о том, как можно назвать перемен­ ную. Не лишним будет повторить изложенные правила, т. к. любая ошибка здесь может привести к синтаксической ошибке при запуске кода. Давайте рассмотрим правила именования переменных, которые всегда нужно помнить. ♦ Имена переменных могут содержать только буквы, цифры и нижние подчерки­ вания. ♦ Несмотря на то что числа использовать можно, имя не должно начинаться с чис­ ла. Имя 5 fingers недопустимо. ♦ В имени нельзя использовать пробелы. Имя написать sales_data. ♦ Имена чувствительны к регистру. Sales и sales data sales — недопустимо. Зато можно это две разные переменные. ♦ Наконец, имена переменных не могут совпадать с ключевыми словами. Это за­ резервированные слова, которые для интерпретатора Python имеют особый смысл, например and, break и try. Чтобы получить список ключевых слов, можно запустить вот такой код, который и выведет список ключевых слов. In [4]: import keyword print(keyword.kwlist) ['False', 'None', 'True', 'continue', 'def, 'del', 'global', 'if, 'import', 'raise', 'return', 'try', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'elif', 'else', 'except', 'finally', 'for', 'from', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'while', 'with', 'yield'] 4.2. Структура программы Прежде чем двигаться дальше, давайте разберем иерархическую структуру про­ граммы. Не пугайтесь новых слов, поскольку мы подробно изучим их позже. В программе на Python можно выделить такие части, как модули, выражения, опе­ раторы и объекты.
Объекты и операторы в Python | 113 ♦ Программы состоят из модулей. ♦ Модули содержат выражения. ♦ Выражения содержат операторы. ♦ Операторы создают и обрабатывают объекты. Итак, модули находятся на вершине иерархии программы, а объекты составляют ее основу. Начнем снизу. Давайте рассмотрим встроенные объекты и выражения, с помощью которых можно работать с этими объектами. 4.3. Объекты Если говорить просто, в Python мы выполняем операции над объектами. Примерами простых операций являются сложение, умножение чисел (как объектов) или конкатенация строк (как объектов). В Python все данные становятся объектами. Объекты могут быть либо встроенны­ ми, которые есть в Python изначально, либо мы создаем их сами с помощью классов Python. Для понимания того, что такое объект, нам пока будет достаточно знать, что это просто «фрагмент памяти», содержащий значение, а также некоторые связанные с объектом операции. Мы вернемся к формальному определению позже в этой главе. Мы также увидим, что в Python все является объектом, будь то простые числа или выполняемые над ними операции. Для скрипта Python все эти вещи являются объ­ ектами. Напомним, что Python поддерживает ООП, т. е. объектно-ориентированное программирование. Важной характеристикой языка Python является то, что его объектная модель очень последовательна. Каждая структура данных, число, строка, класс, функция, модуль и т. д. в интерпретаторе Python существуют в своем собственном «контейнере», ко­ торый называется объектом Python. Каждый объект имеет связанный с ним тип (например, целое число, строка и т. д.) и его данные. На практике это делает язык очень гибким, поскольку даже с функциями можно обращаться так же, как и с лю­ бым другим объектом. 4.3.1. Классификация объектов Объекты делятся по типу данных на: ♦ встроенные; ♦ пользовательские. Типы данных также бывают: ♦ изменяемые; ♦ неизменяемые.
114 | Глава 4 В табл. 4.1 приведены встроенные типы данных, их примеры, а также указано, из­ меняемые они или нет. ТАБЛИЦА 4.1 Тип объекта Примеры объектов Изменяемый или неизменяемый? Числа 1234, 3.1415, 3+4 j, 0Ы11, Decimal!), Fraction!) Неизменяемый Строки 'nilabh1, "Bob's" Неизменяемый Списки [1,[2,'three'),4.5), list(range(10)) Изменяемый Словари ('food':'spam','taste':'yum'}, diet(hours=10) Изменяемый Кортежи (1,'spam',4,'U'), tuple('spam') Неизменяемый Множества set('abc'), {'a','b','c'} Изменяемый Логический тип 0, 1 Неизменяемый Компоненты программы Функции, модули, классы 4.3.2. Преимущества встроенных типов Встроенные типы данных делают важную вещь, благодаря которой Python — это язык высокого уровня. В языках низкого уровня, таких как С и C++, большая часть сил программиста уходит на реализацию объектов или создание структур данных. В этих языках программисту приходится определять тип объекта, раскладывать структуру памяти, управлять выделением памяти и т. д. Эти утомительные и под­ верженные ошибкам действия отвлекают от реальной задачи — от решения постав­ ленной проблемы. В большинстве программ на языке Python можно обойтись без всей этой тяжелой, утомительной и повторяющейся работы. Поскольку в Python есть мощные встроен­ ные типы данных, в большинстве случаев необходимость самому писать реализа­ цию объекта отсутствует. Давайте я приведу аналогию из реальной жизни, чтобы было легче понять, что я имею в виду. В строительстве мостов есть два подхода. Один из них — каждый раз делать все с нуля (рис. 4.1), т. е. отливать каждую сваю и каждую плиту. Такая работа утоми­ тельна и отнимает много времени. Это подход низкоуровневых языков. Все делает­ ся с нуля. Второй подход — использовать готовые элементы (рис. 4.2). В этом случае сваи, плиты и другие конструкционные элементы изготавливаются заранее, и их просто привозят к месту строительства моста и соединяют. Это неутомительный, эффек­ тивный по времени и менее подверженный ошибкам подход. И именно этот подход используется в Python. Типы данных подготовлены заранее. Они уже определены,
Объекты и операторы в Python Рис. 4.1. Мост, построенный с нуля Рис. 4.2. Мост, построенных из готовых элементов | 115
116 | Гпава 4 и пользователю не приходится описывать все нужные объекты с нуля. Это эконо­ мит много времени и усилий, а также снижает количество ошибок. Если нет необходимости в особой обработке данных, которую встроенные типы не обеспечивают, почти всегда лучше использовать встроенный тип данных, а не реа­ лизовывать свой собственный. Тому есть несколько причин: ♦ встроенные типы данных упрощают написание программ; ♦ встроенные типы — это компоненты расширений; ♦ встроенные типы часто более эффективны, чем пользовательские структуры данных; ♦ встроенные типы данных являются стандартной частью языка. Другими словами, встроенные типы данных не только упрощают программирова­ ние, но и гораздо эффективнее типов, которые вы можете создать сами. Независимо от того, создаете ли вы новые типы данных, ядро любой программы на Python все равно состоит из встроенных типов данных. 4.3.3. Идентификаторы, значения и типы объектов Объекты — это абстракция данных Python. Любые данные в программе Python представлены либо объектами, либо отношениями между объектами. Объект можно представить как сочетание трех вещей: ♦ идентификатор; ♦ тип данных; ♦ значение. У каждого объекта есть идентификатор, тип и значение. Идентификатор объекта после его создания никогда не меняется. Это адрес объекта в памяти. В Python идентификатор объекта (или его адрес в памяти) представлен числом. Его можно посмотреть с помощью функции id о. In [5]: |Out[5J: а = 5 # переменная, которой присвоено значение 5 id(а) # адрес в памяти или идентификатор объекта 140703750332944 Тип объекта определяет операции, которые объект поддерживает, а также возмож­ ные значения для объектов этого типа. Функция type () возвращает тип объекта. Как и идентификатор, тип объекта также нельзя изменять. Давайте рассмотрим несколько примеров типов данных, которые были перечисле­ ны в таблице ранее. Подробнее об этих типах мы узнаем в следующих главах. In [6]: type(а) # а присвоено значение 5, которое является целым, # поэтому тип объекта - int |Out[6]: int In [7]: |Out[7]: type('Nilabh') str # str означает строку —
Объекты и операторы в Python In [8]: float In [9]: | Out[9]: type( ['x', In [10]: |Out[10]: In [11]: | Out [11]: □ 'yz', ’abc’]) # список, содержащий три строки □ list type(['x', 117 # число с плавающей точкой type(3.5) |Out[8]: | 'у', 1]) # список из двух строк и одного числа 1 list type ({' food':' spam', 'taste':'yum'}) # словарь diet Есть и другие типы данных, которые вы можете сами проверить, используя функ­ цию type () в своем Jupyter Notebook. 4.3.4. Изменяемые и неизменяемые объекты1 Значение у некоторых объектов может меняться. Объекты, значение которых мо­ жет меняться, называются изменяемыми, а объекты, значение которых после созда­ ния остается постоянным, называются неизменяемыми. Изменяемость объекта определяется его типом; например, числа, строки и кортежи неизменны, а словари и списки — изменяемы. Некоторые объекты содержат ссылки на другие объекты, и тогда они называются контейнерами. Примерами контейнеров являются кортежи, списки и словари. Зна­ чения контейнера — это ссылки на объекты. В большинстве случаев, когда мы го­ ворим о значении контейнера, мы подразумеваем именно значения содержащихся в нем объектов, а не их адреса. Но говоря об изменяемости контейнера, мы имеем в виду только адреса содержащихся в нем объектов. Так, если неизменяемый кон­ тейнер (например, кортеж) содержит ссылку на изменяемый объект, значение кон­ тейнера изменится при изменении значения объекта. Однако контейнер попрежнему считается неизменяемым, поскольку набор содержащихся в нем объек­ тов не может быть изменен. Получается, что неизменяемость контейнеров — это не то же самое, что невозможность изменить значение, тут все чуть сложнее. 4.4. Стандартная иерархия типов2 Далее приведен список встроенных типов Python. Используя функцию typed, вы можете самостоятельно рассмотреть все перечисленные типы в Jupyter Notebook, чтобы попрактиковаться и лучше их понять. Только тогда самые сложные концеп­ ции станут ясными, как день. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21]. 2 Python Reference Manual, 2002 (https://docs.python.Org/2.l/ref/types.html) [20]. 1
118 | Гпава 4 4.4.1. Встроенные константы ♦ None У этого типа данных одно-единственное значение. И есть только один объект с таким значением. Доступ к этому объекту осуществляется через встроенное имя None. Он используется для обозначения отсутствия значения, например воз­ вращается из функций, которые ничего явно не возвращают. В логическом смысле эквивалентен False. ♦ Notlnplemented У этого типа одно-единственное значение. И это единственный объект с таким значением. Доступ к этому объекту осуществляется через встроенное имя Not implemented. Числовые методы и методы сравнения должны возвращать этот объект, если они не реализуют операцию для предоставленных операндов. В ло­ гическом смысле эквивалентен True. ♦ Ellipsis У этого типа одно-единственное значение. И это единственный объект с таким значением. Доступ к этому объекту осуществляется через литерал ... или встро­ енное имя Ellipsis. В логическом смысле эквивалентен True. 4.4.2. Числовые типы Они создаются числовыми литералами и возвращаются арифметическими операто­ рами и встроенными арифметическими функциями в качестве результата. Число­ вые объекты неизменяемы, т. е. после создания их значения не меняются. Числа в Python, разумеется, связаны с числами в реальной математике, но с учетом огра­ ничений компьютерного числового представления. Python различает целые числа, числа с плавающей точкой и комплексные числа. ♦ Целые числа (int) Это целые числа в неограниченном диапазоне, зависящем только от доступной (виртуальной) памяти. Для операций сдвига и маски используется двоичное представление, а отрицательные числа представлены в дополнительном коде, что создает иллюзию бесконечной строки знаковых битов, простирающейся влево. ♦ Логические значения (bool) Единственными логическими объектами являются True и False, представляющие логические значения. Логический тип является подтипом целочисленного, т. к. логические значения ведут себя как значения 0 и 1 почти во всех случаях, за ис­ ключением того, что при преобразовании в строку возвращаются строки "True" и "False" соответственно. ♦ Вещественные числа (float) Это числа с плавающей точкой двойной точности машинного уровня. Здесь диа­ пазон значений и обработка переполнений задаются на уровне базовой машин-
Объекты и операторы в Python | 119 ной архитектуры (и реализации С или Java). Python не поддерживает числа с плавающей точкой одинарной точности, т. к. экономия на ресурсах процессора и памяти, которая обычно является причиной их использования, перекрывается накладными расходами на использование объектов в Python, поэтому нет при­ чин усложнять язык двумя видами чисел с плавающей точкой. ♦ Комплексные числа (complex) Комплексные числа представляются как пара чисел с плавающей точкой двой­ ной точности машинного уровня. Ограничения те же, что и у чисел с плавающей запятой. Действительную и мнимую части комплексного числа z можно полу­ чить С ПОМОЩЬЮ атрибутов z. real И z. imag. 4.4.3. Последовательности Это конечные упорядоченные множества с индексацией неотрицательными числа­ ми. Встроенная функция 1еп() возвращает количество элементов последователь­ ности. Когда длина последовательности равна п, ее индексы лежат в диапазоне О, 1,..., п-1. Чтобы выбрать z-й элемент последовательности а, нужно напи­ сать a[i]. Последовательности также поддерживают операции срезов. Срез a[i:j] выбирает все элементы с таким индексом к, что выполняется неравенство 1 <= к < j. При использовании в выражении срез представляет собой последовательность того же типа. Это означает, что сам по себе срез тоже проиндексирован с 0. Некоторые последовательности также поддерживают «расширенные срезы» с третьим параметром— шагом. Срез a[i:j:k] выбирает все элементы а с индек­ сом х, где выполняются условия: х = i + n * k, п >= о и i <= х < j. Последовательности можно разделить на группы по признаку изменяемости. 4.4.3.1. Неизменяемые последовательности Неизменяемые последовательности не могут быть изменены после создания. Если объект содержит ссылки на другие объекты, то эти другие объекты могут изме­ няться, но коллекция объектов, на которые ссылается эта неизменяемая последовальность, измениться не может. Перечисленные типы являются неизменяемыми. ♦ Строки (str) Строка— это последовательность значений, кодируемых таблицей Unicode. В Python нет типа char, а символы представляются как строки длиной 1. Строки в Python заключаются в одинарные или двойные кавычки. Строки 'привет' И "привет" идентичны. Любые символы в диапазоне кодов от и+оооо до u+ioffff могут быть представле­ ны в виде строки.
120 | Глава 4 Встроенная функция ord о переводит код символа из строковой формы в целое число в диапазоне от о до ioffff, а функция chr() преобразует целое число в диа­ пазоне от о до ioffff в соответствующий строковый объект длиной 1. In [12]: bytes(b'nilabh') |Out[12]: b'nilabh' In [13]: 'nilabh' # строка, символ 'n' находится на 0-м индексе, # a 'h' - на 5-м 'nilabh'[3] |Out[13]: In [14]: |Out [14]: In [15]: |Out[15]: In [16]: |Out[16]: In [17]: # срез строки по индексу 3 дает "а" 'а' ord('nilabh'[3]) # это то же самое, что и ord ('а') 97 ord('a') 97 chr(97) # функция chr() переводит целое число в символ 'а' print(chr(96)) print(chr(100)) print(chr(99)) print(chr (1045)) print(chr(100009)) d c E @ Рекомендую вам поэкспериментировать с функцией chr о и передавать ей в ка­ честве параметра разные числа, чтобы убедиться, что каждый строковый объект единичной длины может быть представлен целым числом. Затем попробуйте наоборот — преобразовывать строки единичной длины с по­ мощью функции ord(), и в результате увидите коды символов. ♦ Кортежи (tuple) Элементами кортежа могут быть любые объекты Python. Кортеж из двух или более элементов формируется из списка выражений, разделенных запятыми. Кортеж из одного элемента можно создать путем добавления запятой к выраже­ нию (выражение само по себе не является кортежем, а для группировки выраже­ ний в кортеж необходимо использовать круглые скобки). Пустой кортеж можно задать пустой парой круглых скобок. Пример кортежа: ('xyz', 5, 'р').
Объекты и операторы в Python | 121 ♦ Байтовые строки (bytes) Объект типа bytes — это неизменяемый массив. Его элементы представляют со­ бой 8-битные числа х, такие что о <= х < 256. Для создания байтовых строк мож­ но использовать байтовые литералы (например, b'abc') или встроенный конст­ руктор bytes (). Кроме того, байтовые строки можно декодировать в строки с по­ мощью метода decode (). 4.4.3.2. Изменяемые последовательности Изменяемые последовательности допускают их изменение после создания. При выполнении операций присваивания и удаления можно использовать индексы и срезы. В языке Python существуют два внутренних типа изменяемых последователь­ ностей: ♦ Списки (list) Элементами списка могут быть произвольные объекты Python. Списки форми­ руются путем передачи списка выражений, разделенных запятыми, заключенно­ го в квадратные скобки (обратите внимание, что для формирования списков длины 0 или 1 особых обозначений не требуется). Пример списка: ['xyz', 5, 'р']. ♦ Байтовые массивы (bytearray) Объект bytearray— это изменяемый массив. Такие массивы создаются встроен­ ным конструктором bytearray(). Кроме того, что байтовые массивы являются изменяемыми (и, следовательно, нехешируемыми), у них тот же интерфейс и функциональность, что и у неизменяемых байтовых объектов. 4.4.4. Множества Множества — это неупорядоченные конечные наборы уникальных неизменяемых объектов. Множества не индексируются, но можно перебирать их элементы в цик­ ле, а встроенная функция 1еп () возвращает количество элементов в наборе. Обычно множества используются для быстрой проверки вхождения элемента, уда­ ления дубликатов из последовательности и вычисления математических операций над множествами, таких как пересечение, объединение, разность и симметричная разность. Для элементов множества применяются те же правила неизменяемости, что и для ключей словаря. Обратите внимание, что числовые типы сравниваются по обыч­ ным правилам числового сравнения, т. е. если два числа считаются равными (на­ пример, 1 и 1.0), то лишь одно из них может содержаться во множестве.
122 | Глава 4 В настоящее время существуют два встроенных типа множеств: ♦ Множества (set) Это изменяемые множества. Они создаются встроенным конструктором set() и впоследствии могут быть изменены некоторыми методами, такими как add (). Пример множества: {"apple", "banana", "cherry"}. ♦ Замороженные множества (frozenset) Это неизменяемые множества. Они создаются встроенным конструктором frozenset о. Поскольку этот тип является неизменяемым и хешируемым, его можно включать в другие множества или использовать в качестве ключа сло­ варя. Примечание Множества неупорядочены, поэтому их элементы возвращаются в случайном порядке. В Python множества заключаются в фигурные скобки. Обращаться к элементам мно­ жества по индексам нельзя, поскольку множества неупорядочены, и у их элементов нет индекса. 4.4.5. Сопоставления Сопоставления представляют собой конечные наборы объектов, индексированных произвольными индексами. Обращение вида а [к] позволяет выбрать из сопоставле­ ния а элемент с индексом к. Этот синтаксис можно использовать в выражениях, в операторах присваиваний и в операторах del. Встроенная функция 1еп() возвра­ щает количество элементов в сопоставлении. В настоящее время в языке Python существует один тип сопоставления: ♦ Словарь (diet) Словарь представляет собой конечный набор объектов с почти произвольными индексами (ключами). В качестве ключей можно использовать все типы, кроме типов вроде списков или других словарей, которые являются изменяемыми и сравниваются по значению, а не по идентификатору объекта. Все дело в том, что для эффективной реализации словарей требуется, чтобы хеш-значения ключей не менялись. Числовые типы, используемые в качестве ключей, подчиняются обычным правилам числового сравнения: если два числа являются равными (на­ пример, 1 и 1.0), то они оба могут использоваться для индексации одного и того же элемента словаря. Словари изменяемы. Создать словарь можно с помощью фигурных скобок {}. Пример словаря: {"марка": "Форд", "модель": "Мустанг", "год": 1964}. 4.4.6. Вызываемые типы Это типы объектов, к которым может применяться операция вызова функции: ♦ Встроенные функции Функция — это блок кода, который запускается только при ее вызове. В функ­ цию можно передавать параметры. В конце выполнения функция может вернуть
Объекты и операторы в Python какие-то данные. Примеры встроенных функций: стандартный встроенный модуль). 1еп() и | math.sin() (math— 123 это Чтобы вызвать функцию, нужно написать имя функции, а за ним круглые скоб­ ки. Например, 1еп О —это функция, которая возвращает длину строки. ♦ Пользовательские функции Пользовательская функция создается с помощью определения функции (под­ робнее об этом в следующих главах). Функция вызывается со списком аргумен­ тов, в котором должно быть то же количество элементов, что и в списке фор­ мальных параметров функции в определении. ♦ Методы Метод экземпляра объединяет класс, экземпляр класса и любой вызываемый объект (обычно пользовательскую функцию). ♦ Встроенные методы На самом деле это то же самое, что и встроенные функции. Метод в Python по­ хож на функцию, за исключением того, что он относится к объекту. Вызывая метод объекта, мы, вероятно, вносим в этот объект изменения. Таким образом, метод принадлежит классу. Примером является метод добавления элемента в СПИСОК append (). Примечание • Методы, в отличие от функций, вызываются у конкретного объекта. • Функции вызываются сами по себе, т. е. они не привязаны к объектам. • Поскольку метод вызывается у объекта, он может обращаться к его внутренним данным. • Метод может изменять состояние объекта, а функции обычно что-то принимают на вход, а в ответ возвращают значение или выводят что-то на экран. ♦ Классы Классы относятся к вызываемым объектам и объединяют в себе данные и функ­ циональность. Создание нового класса позволяет создать новый тип объектов, а в дальнейшем и новые экземпляры этого типа. Каждый экземпляр класса хранит атрибуты, определяющие его состояние. Экземпляр класса также может иметь методы (определяемые этим классом), изменяющие его состояние. 4.4.7. Модули В целом модуль — это то же самое, что и библиотека кода, т. е. файл с набором функций, которые вы хотите добавить в свое приложение. Чтобы создать модуль, достаточно лишь сохранить нужный код в файле с расширением ру. После этого вновь созданный модуль можно импортировать с помощью оператора import. Модуль может содержать функции, а также переменные всех типов (массивы, сло­ вари и т. д.).
124 | Глава 4 Модули являются базовым элементом кода Python и создаются с помощью опера­ тора import или при вызове таких функций, как importlib.importjnodule() или import(). 4.5. Операции с объектами в Python Пока что мы занимались в основном теорией. Теперь давайте применять новые знания на практике. Начнем с самых простых задач — ввод текста и печать. Под словом «печать» здесь и далее подразумевается вывод на экран, а не распечатка бумажной копии с принтера. In [18] : | Out [18] : In [19]: 14 + 26 40 1.5 * 4 |Out[19]: 6.0 In [20]: |Out[20]: 2**100 In [21]: 4/2 2.0 In [22]: # умножение вещественных чисел # 2 в степени 100 1267650600228229401496703205376 |Out[21]: |Out[22] : # целочисленное сложение 5 > 4 # деление всегда возвращает число с плавающей точкой # логическое выражение True Здесь приведены примеры простых арифметических операций, которые можно лег­ ко выполнять в Python с помощью Jupyter Notebook, Spyder IDE или консоли. Стоит обратить внимание на несколько моментов. ♦ Мы не запрашиваем вывод результатов в явном виде. Результат печатается сам по себе при запуске кода. ♦ Текст, написанный после символа #, пропускается и не считается частью кода. ♦ Поэтому в коде рекомендуется писать комментарии после символа #, чтобы сде­ лать программу более читаемой. 4.6. Операторы' Код, которые вы пишете, в основном состоит из выражений. Простой пример вы­ ражения — 2 + з. В выражении можно выделить операторы и операнды. Операто­ ры — это какие-то действия. Они могут быть представлены символами, такими как +, или специальными ключевыми словами. Операторам для работы нужные дан- 1 Swaroop, 2003 (https://python.swaroopch.com/) [39].
Объекты и операторы в Python ные, которые называются операндами. В приведенном примере числа ся операндами. 2 | 125 и з являют­ Мы подробно рассмотрим принцип работы операторов, разделив их на 4 большие группы. 4.6.1. Арифметические операторы Оператор Операция + Сложение - Вычитание * Умножение / Деление % Остаток от деления // Целочисленное деление ** Возведение в степень Далее рассмотрим примеры использования каждого оператора. ♦ + (плюс) Складывает два объекта. дает • 4 + з • 'а' + 'Ь' 7. дает 'аЬ'. ♦ -(минус) Выполняет вычитание одного числа из другого. Если первый операнд отсутст­ вует, предполагается, что он равен нулю. дает отрицательное число. • -2.8 • 70 - 34 дает 36. ♦ * (умножение) Возвращает произведение двух чисел или повторяет строку заданное число раз. дает • 2*3 • ' ля' * з 6. дает 1 ляляля'. ♦ ** (степень) • х ** у возвращает х в степени • 2 ** 3 возвращает у. 8. ♦ / (деление) • х / у делит • 13 / з дает число х на число 4,ззззззззззззззз. у.
| 126 Гпава 4 ♦ // (целочисленное деление) х // у делит х на у и округляет ответ до ближайшего целого числа. При этом, если одно из чисел является дробным, ответ тоже будет числом с плавающей точкой. дает • 13 // з • -13 // з • 9 // 1.81 4. дает -5. дает 4.0. ♦ % (остаток от деления) Возвращает остаток от деления. дает • 13 % з • -25.5 % 2.25 1. дает 1.5. 4.6.2. Операторы присваивания Оператор Выражение Эквивалент = а - Ь — += а += Ь а = (а + Ь) -= а -= b а = (а - Ь) * —5 а *= b а = (а * Ь) /= а /= Ь а = (а / Ь) %= а %= b а = (а % Ь) //= а //= b а = (а // Ь) * *= а **= Ь а = (а ** Ь) Эти операторы используются для присвоения переменным значений. Важно помнить, что оператор = означает присваивание, а не равенство, и не путай­ те его с оператором равенства ==. В приведенной таблице в первом примере пере­ менной а присваивается значение, содержащееся в переменной ь, и после этого в переменной а хранится уже новое значение. Оператор += сначала добавляет к значению, содержащемуся в переменной а, значе­ ние переменной ь. Затем он присваивает переменной а результат этого сложения. Все остальные операторы работают похожим образом: сначала выполняют арифме­ тическую операцию между двумя значениями, а затем присваивают результат этой операции первой переменной. При выполнении оператора %= первый операнд а делится на второй операнд ь, затем остаток от этого деления присваивается переменной а.
Объекты и операторы в Python | 127 4.6.3. Операторы сравнения Оператор Операция == Равенство != Неравенство > Больше < Меньше >= Больше или равно <= Меньше или равно Краткое описание операторов: ♦ == (равно) Проверяет равенство объектов. Например: возвращает True. • х = 2; у = 2; х == у • х = 'str'; у = 'stR'; х == у возвращает False. • х = 'str'; у = 'str'; х == у возвращает True. ♦ ! = (не равно) Проверяет неравенство объектов. Например: х = 2; у = 3; х != у возвращает True. ♦ < (меньше) проверяет, действительно ли нения, возвращает True ИЛИ False. х < у 6 < 4 дает False, а 4 < 6 х меньше у. Как и все прочие операторы срав­ дает True. Сравнения можно соединять в цепочки: например, з < 5 < 7 дает True. ♦ > (больше) х > у проверяет, действительно ли х больше у. возвращает True. Если оба операнда являются числами, они сначала приво­ дятся к общему типу. В противном случае всегда возвращает False. 6 > 4 ♦ <= (меньше или равно) х <= у проверяет, действительно ли х = 3; у = 6; X <= у х меньше или равно у. больше или равно у. возвращает True. ♦ >= (больше или равно) х >= у проверяет, действительно ли х = 4; у = 3; х > = 3 х возвращает True.
128 | Глава 4 4.6.4. Логические операторы Оператор Операция not Логическое НЕ and Логическое И or Логическое ИЛИ Краткое описание операторов: ♦ not (логическое НЕ) • Если х равен True, возвращает • Если х равен ♦ and (логическое • False, False. возвращает True. И) возвращают значение возвращается значение у. х and у False, если х равно False, в противном случае • Пусть х = False; у = True. Тогда х and у возвращают False, поскольку х имеет значение False. В этом случае Python не будет вычислять значение у, по­ скольку знает, что левая часть выражения and имеет значение False, и поэтому все выражение будет равно False независимо от других значений. Это назы­ вается сокращенной оценкой логического выражения. ♦ or (логическое ИЛИ) • Если х равен True, возвращает True, • Пусть х = True; у = False. Тогда х выполняться сокращенная оценка. иначе возвращает оценку or у возвращает True. у. Здесь также может 4.6.5. Операторы идентификации и вхождения Оператор Выражение Операторы идентификации is x is у is not x is not у Операторы вхождения in x in у not in x not in у Краткое описание операторов: ♦ Операторы идентификации проверяют идентичность двух объектов. • is Если если х — это тот же объект, что и тивном случае возвращается False. у, выражение возвращает True. В про­
Объекты и операторы в Python | 129 выражение возвращает True. is not Если х не является тем же объектом, что и В противном случае возвращается False. у, ♦ Операторы вхождения проверяют, является ли данный объект элементом дан­ ной коллекции. Под «коллекцией» понимается последовательность или структу­ ра данных, например строка, список, кортеж и т. д. • in Если х является элементом коллекции случае возвращается False. • у, то возвращается True, в противном возвращается True, в противном not in Если х не является элементом коллекции случае возвращается False. у, Примеры использования этих операторов: In [23]: |Out[23]: In [24]: |Out[24]: In [25]: 4 is 2 * 2 True "i" in "string" True x = [1, 2, 3, "three", 4] print(2 in x) print(5 in x) print("three" in x) True False True 4.7. Отступы Одним из наиболее ярких преимуществ Python является выделение блоков кода с помощью отступов. В большинстве других языков программирования отступы используются лишь для того, чтобы код выглядел красиво. В Python же они опре­ деляют, к какому блоку кода принадлежит выражение. В большинстве языков программирования, таких как С, C++, Java, для выделения блока кода используются фигурные скобки {]. В Python для этого используются отступы. Блок кода (тело функции, цикла и т. д.) начинается с отступа и заканчивается, когда появляется строка без такого отступа. Величина отступа остается на усмотрение программиста, но она должна быть одинаковой во всем блоке. Обычно для отступа используются четыре пробела, и такой способ считается предпочтительнее табуляции. Например:
| 130 Гпава 4 In [26]: if True: print('Hello') |Hello In [27]: if True: print('Hello') File "<ipython-input-27-78e5790belca>", line 2 print('Hello') Л IndentationError: expected an indented block Неправильный отступ приводит К возникновению ошибки IndentationError. 4.8. Комментарии в Python Комментарии при написании программы весьма полезны. Они делают код более читабельным и позволяют понять, что делается в программе. Благодаря коммента­ риям человеку, просматривающему исходный код, не составит труда разобраться в нем. Даже сам программист может забыть подробности программы, написанной им же самим несколько месяцев назад. Поэтому оставлять в коде пояснения в фор­ ме комментариев всегда полезно. В Python комментарии начинаются с символа решетки #. Интерпретатор Python комментарии игнорирует. 4.9. Порядок выполнения Порядок вычисления в математическом уравнении вам наверняка известен со шко­ лы: сначала скобки, затем степень, деление, умножение, сложение и вычитание, в порядке слева направо. В Python тоже есть собственный приоритет операторов'. В табл. 4.2 приведена справка по приоритету операторов в Python от наивысшего приоритета (наибольшая привязка) до самого низкого приоритета (наименьшая привязка). Операторы, расположенные в одной строке, имеют одинаковый приори­ тет. Если синтаксис не указан явно, операторы являются бинарными. Операторы одного приоритета выполняются слева направо (за исключением возведения в сте­ пень, которое выполняется справа налево). ТАБЛИЦА 4.2 Оператор Описание (выражения ...), [выражения...], {ключ: значение...}, {выражения__ } Запаковка кортежа, списка, словаря или множества 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Объекты и операторы в Python | 131 ТАБЛИЦА 4.2 (окончание) Оператор Описание х [индекс], х [индекс: индекс], ■л (аргументы ...), х.attribute Индексация, срезы, вызовы, ссылки на атрибуты await х Оператор await ** Возведение в степень +х, -х, ~х Смена знака числа, побитовое НЕ *, 0, /, //, % Умножение, матричное умножение, деление, целочисленное деление и остаток +, - Сложение, вычитание «, » Сдвиг & Побитовое И Побитовое исключающее ИЛИ in, not in, is, is not, <, <=, >, >=, !=, == Сравнения, проверка вхождения и типа not X Логическое НЕ and Логическое И or Логическое ИЛИ if-else Условный оператор lambda Лямбда-выражение 4.9.1. Изменение порядка выполнения Чтобы выражения были более удобочитаемыми, можно использовать круглые скобки. Например, выражение 2 + (3 * 4) определенно читается легче, чем 2 + з * 4, т. к. в последнем случае требуется знать приоритет операций. Как и с ос­ тальными инструментами, круглые скобки следует использовать разумно (важно не переусердствовать) и не вставлять лишних, как здесь: (2 + (3 * 4)). Использование круглых скобок дает дополнительное преимущество — оно позво­ ляет управлять порядком выполнения. Например, если вы хотите, чтобы в выраже­ нии вычислялось сперва сложение, а затем умножение, можно записать следующим образом: (2 + 3) * 4. 4.9.2. Ассоциативность Операторы с одинаковым приоритетом вычисляются слева направо. Например, за­ пись 2+3+4 эквивалентна (2 + 3) + 4. Исключение составляет только оператор возведения в степень ** — он имеет ассоциативность справа налево.
132 | Гпава 4 4.9.3. Площадь прямоугольника Давайте напишем простую программу, которая поможет нам понять все концепции, введенные до сих пор. Это также поможет вам избавиться от страхов, которые у вас могли быть, и осознать, насколько на самом деле легко написать код на Python. In [28]: # вычисление площади прямоугольника Length = 5 Width = 8 Area = Length * Width print("Area of the Rectangle is", Area) print("Perimeter of the rectangle is", 2 * (Length + Width)) Area of the Rectangle is 40 Perimeter of the rectangle is 26 Давайте посмотрим на код, который мы только что написали. Длина и ширина прямоугольника хранятся в переменных с соответствующими именами. Но важно помнить, что length и Length — это разные имена. Всегда пом­ ните, что Python чувствителен к регистру. Следовательно, length отличается от Length ИЛИ LENGTH. Мы используем заданные переменные для вычисления площади и периметра пря­ моугольника с помощью выражений. Результат выражения Length * Breadth сохра­ няется в переменной Area, а затем мы выводим его с помощью функции print (). Во втором случае мы напрямую используем выражение для вычисления периметра прямоугольника в функции print (). Также обратите внимание, как Python красиво оформляет вывод. Несмотря на то ЧТО МЫ не указали пробел между 'Area of the Rectangle is' И переменной Area, Python сам добавляет его, чтобы вывод был более читаемый (это удобно, поскольку не нужно думать о пробелах в строках, которые мы выводим). Это пример того, как Python упрощает жизнь программисту. 4.10. Динамическая типизация В Python значение, на которое указывает переменная, имеет определенный тип данных, но сама переменная не имеет строгого типа. Вы можете повторно исполь­ зовать одну и ту же переменную, передавая ей ссылку на объект уже другого типа. Переменные можно считать «ярлыками», связанными с объектами. In [29]: six = 6 six |Out[29]: In [30]: 6 six = 'six' six |Out[30]: 'six'
Объекты и операторы в Python | 133 4.11. Строгая типизация Хотя Python позволяет гибко обходиться с типами данных, вам тем не менее нужно знать, объекты каких типов вы используете. Для некоторых операций требуются аргументы определенного типа. In [31]: 'day' + 1 Traceback (most recent call last) TypeError <ipython-input-31~91cbf6ala000> in <module> --- > 1 'day'+l TypeError: can only concatenate str (not "int") to str В Python тип объекта можно явно изменить с помощью встроенных функций. In [32]: |Out[32]: 'day ' + str('1') 'day 1' 4.12. Логическая и физическая строка Физическая строка кода — это то, что вы буквально видите на экране, когда пише­ те программу. Логическая строка— это то, что Python считает единым выпол­ няемым выражением. Python неявно предполагает, что каждая физическая строка соответствует логической строке. Это легко понять на примерах. In [35]: # здесь две физические и две логические строки i = 5 print(i) |5 Здесь оператор i = 5 — это и физическая, и логическая строка. И функция print (i) — это тоже и физическая, и логическая строка. Вы можете спросить: а в чем тогда разница? In [36]: # здесь одна физическая строка, но две логические i = 5; print(i) I5 Теперь вы видите разницу! Python видит здесь две разные строки (логические строки), а вы, как программист, видите одну физическую строку. И зачем нам это? Если вы хотите записать более одной логической строки на одной физической строке, вы должны использовать точку с запятой (, ), которая отмечает конец логи­ ческой строки/оператора.
134 | Гпава 4 Например: i = 5 print (i) фактически то же самое, что и: i = 5; print(i); а также: i = 5; print(i); и вот это: i = 5; print(i) Python поощряет использование одного выражения в строке. Это делает ваш код более читабельным. Я поддерживаю этот подход и настоятельно рекомендую вам писать не более одной логической строки на каждой физической строке кода. В идеале вы никогда не должны использовать точку с запятой. Это сделает ваш код более читабельным не только для вас, но и для ваших коллег. 4.13. Резюме В этой главе мы изучили семантику языка Python, а также подробнее рассмотрели некоторые темы, которых мы уже касались в предыдущей главе. Эти знания столь же важны, сколь и грамматика английского языка. Мы рассмотрели иерархию и структуру кода Python. Мы узнали, что в Python все является объектом. Мы узнали о разных типах объектов и их иерархии. Мы видели, что выражения, операторы и операнды— это основные строительные блоки любой программы. Позже мы увидим, как использовать их в наших программах. 4.14. Упражнения 4.14.1. Ответьте на вопросы 1. Что такое переменная в Python? Чем она отличается от объекта? 2. Каковы правила именования переменных в Python? Напишите, какие имена можно использовать, а какие нельзя. 3. В чем преимущества встроенных типов данных? 4. Что такое неизменяемый объект? Какие объекты в Python неизменяемы? 5. Что называется идентификатором объекта? Чем он отличается от типа? 6. Что делают функции chr () и ord о ? Как они связаны? 7. Что такое оператор! Сколько типов операторов существует в Python? Назовите их все.
Объекты и операторы в Python | 135 8. Операторы / и // выполняют деление. В чем разница между ними? 9. Какое значение возвращают логические операторы? 10. В чем важность отступов в языке программирования Python? 11. Как писать комментарии на Python? Для чего они нужны? 12. Как изменить порядок выполнения операторов в Python? 13. В чем разница между логической строкой и физической строкой кода? 4.14.2. Правда или ложь 1. Переменные в Python получают присвоенное им значение. 2. В Python перед созданием переменной необходимо сначала определить ее тип. 3. Выражения х = 38 и х == 38 означают не одно и то же. 4. В Python мы выполняем операции над объектами. 5. Ключевые слова Python можно использовать в качестве имен переменных. 6. Пользовательские типы данных работают эффективнее, чем встроенные. 7. Идентификатор объекта никогда не меняется после его создания. 8. Комментарии делают программу более читаемой и простой для понимания. 9. Отступы — это лишь украшение и способ сделать программу более красивой и читаемой. 10. Оператор % возвращает остаток от деления двух чисел. 4.14.3. Практические задания 1. Питер получает зарплату 12 000 в месяц. Напишите код для вычисления его сбе­ режений к концу года, если он будет откладывать 20% своей зарплаты каждый месяц. 2. Расстояние между Мумбаи и Дели составляет 1422 км. Если Сундар едет на ма­ шине со средней скоростью 72 км/ч, сколько времени ему потребуется, чтобы преодолеть это расстояние? 3. Температура тела человека находится в диапазоне от 97 до 99° по Фаренгейту. Как этот диапазон будет выглядеть в градусах Цельсия? 4. Пусть дано шестизначное число. Напишите программу для вычисления суммы всех цифр этого числа. 5. У нас есть данные о месячных продажах 5 книжных магазинов в Бруклине: А = $ 6500, В = $ 8000, С = $ 12 000, D = $ 4900 и Е = $ 5600. Предполагая, что в Бруклине всего 5 книжных магазинов, узнайте рыночную долю каждого магазина. Также проверьте, какой будет сумма рыночных долей всех магазинов. (Рыночная доля означает отношение одного участника ко всем остальным.)
136 | Гпава 4 6. Среднее значение трех чисел равно 45. Первое число больше среднего значения настолько же, насколько второе число меньше среднего значения. Найдите третье число. 7. Джон покупает мобильный телефон за 1800 в Калькутте и продает его в Мум­ баи с прибылью 25%. Если его накладные расходы составляют 5% от цены продажи, то какова цена продажи? 8. Найдите объем и площадь куба с диагональю 5 м. Подсказка: V = -^=, S = 2d2. зТз 9. Три металлических куба с ребрами длиной 3, 4 и 5 см соответственно пере­ плавляются в один куб. Найдите длину ребра нового куба. 10. Дано шестизначное число. Напишите программу для получения числа с обрат­ ным порядком цифр. 4.14.4. Изучите самостоятельно 1. Почитайте об операторах и их иерархии в математике. 2. Чтобы по-настоящему понять, что происходит, не читайте эту книгу как забав­ ную историю. Попробуйте выполнить каждую строку кода в Spyder IDE или Jupyter Notebook. 3. Изучая приведенные в книге фрагменты кода, экспериментируйте сами. Про­ буйте менять что-то в коде, в синтаксисе или семантике и анализировать, что получилось. 4. Попробуйте создать в Jupyter Notebook несколько ячеек Markdown, примените к ним разное форматирование.
5 Операторы управления потоком 5.1. Управление потоком Как мы видели в предыдущей главе, написанный нами простой код выполнялся в том порядке, в котором он написан, т. е. операторы выполнялись один за другим последовательно сверху вниз. А что делать, если мы хотим изменить направление выполнения кода? Что если мы хотим, чтобы один блок кода выполнился раньше другого, в зависи­ мости от какого-то условия? Что если нам нужно, чтобы программа выполняла разные действия в зависимости от тех или иных обстоятельств? Например, когда нам нужно выводить текст «Чет­ ное число» или «Нечетное число» в зависимости от введенного числа. Ответом на эти и многие другие вопросы являются операторы управления пото­ ком. Они составляют основу любого языка программирования, и в Python они тоже есть (рис. 5.1). Рис. 5.1. Операторы управления потоком 5.2. Операторы if 5.2.1. Простой оператор if Оператор if используется для проверки условия и, если условие истинно, выполня­ ется связанный с оператором блок кода (называемый блоком if).
138 | Гпава 5 Синтаксис: ключевое слово if, условие и двоеточие. Блок кода оператора if начи­ нается со следующей строки и должен иметь отступ. Отступ сообщает Python о том, что этот блок кода предназначен для оператора if. if условие: код блока if конец блока if Строка конец блока if не пишется, блок оператора заканчивается сам по себе. Это будет видно в приведенном далее примере. Объясню с помощью блок-схемы, как меняется выполнение кода (рис. 5.2). Рис. 5.2. Блок-схема оператора if Попробуйте выполнить следующий код в своем Jupyter Notebook или IPython. Экс­ перимента ради вы можете попробовать другие входные данные и сравнить резуль­ таты. In [1]: if 8 > 5: print("8 is greater than 5") 8 is greater than 5 Давайте посмотрим еще на один пример того, что происходит, когда условие не выполняется: In [2]: if 8 < 5: print("8 is less than 5") Как вы могли убедиться, результат не вывелся. Поскольку условие if не было вы­ полнено, блок кода if тоже не выполнился, и программа завершилась сама собой. Давайте рассмотрим, как с помощью оператора if решить реальную проблему. Реальная ситуация: перед праздником в торговом центре объявили распродажу. При покупке электронных товаров вам предлагается скидка 20% при условии, что сумма покупки превышает 50 000. Клиент покупает некоторое количество товаров, суммарная стоимость купленных товаров вводится с клавиатуры. Нужно написать программу для вычисления суммы, подлежащей оплате.
Операторы управления потоком | 139 Решение: In [3]: а = int(input("Общая сумма покупаемых товаров: ")) discount = О if а > 50000: discount = (а * 20)/100 bill_amount = а - discount print("Итоговая сумма к оплате: {}, скидка составила: {}" .format(bill_amount, discount)) Общая сумма покупаемых товаров: 80000 Итоговая сумма к оплате: 64000.0, скидка составила: 16000.0 5.2.2. Оператор if-else В большинстве случаев бывает нужно что-то сделать, если условие if не выполни­ лось, т. е. оказалось ложно. Для этого у нас есть оператор if-else (рис. 5.3). Рис. 5.3. Блок-схема оператора if-else Как и ранее, оператор if проверяет условие: если условие истинно, запускается блок if, в противном случае выполняется другой блок операторов (называемый блоком else). При этом блок else не является обязательным. if условие: код блока if else: код блока else Синтаксис: ключевое слово условие и двоеточие. Блок if начинается со сле­ дующей строки и должен иметь отступ. Отступ сообщает Python о том, что этот блок кода предназначен для оператора if. Затем идет ключевое слово else на новой строке без отступа, за ним следует двоеточие. Блок кода оператора else начинается со следующей строки с отступом. Отступ сообщает Python о том, что этот блок кода предназначен для оператора else. if, Попробуйте выполнить следующий код в Jupyter Notebook или IPython. Чтобы по­ практиковаться, мы использовали здесь функцию input О, которая запрашивает данные от пользователя. Вы можете попробовать разные входные данные и срав­ нить результаты.
140 | In [4]: Глава 5 num = int(input("Enter a number: ")) if num > 11: print ("{} is greater than 11". format)num)) else: print ("{} is smaller than 11".format(num)) Enter a number: 15 15 is greater than 11 Давайте посмотрим, как использовать оператор дачи. if-else для решения реальной за­ Реальная ситуация: перед праздником в торговом центре объявили распродажу. При покупке одежды и модных аксессуаров вам предлагается скидка 20% при условии, что сумма покупки превышает 25 000, в противном случае скидка состав­ ляет 5%. Клиент покупает некоторое количество товаров, суммарная стоимость купленных товаров вводится с клавиатуры. Напишите программу для вычисления суммы, подлежащей оплате. Решение: In [5]: а = int(input("Общая сумма покупаемой одежды и аксессуаров: ")) if а > 25000: discount = (а * 20)/100 else: discount = (а * 5)/100 bill_amount = а - discount print("Итоговая сумма к оплате: {}, скидка составила: (}" .format(bill_amount, discount)) Общая сумма покупаемой одежды и аксессуаров: 20000 Итоговая сумма к оплате: 19000.0, скидка составила: 1000.0 5.2.3. Оператор if-elif-else Из названия ясно, что elif — это комбинация else и if. Блок-схема работы этого оператора облегчит вам понимание концепции (рис. 5.4). Рис. 5.4. Блок-схема оператора if-elif
Операторы управления потоком In [6]: | 141 х = int(input("Please enter an integer: ")) if x < 0: print('Negative Number') elif x == 0: print('Zero') elif x == 1: print('Single') else: print('More') Please enter an integer: 4 More Блоков elif может быть сколько угодно (или их может не быть вовсе), а блок else необязателен. Ключевое слово elif является сокращением от else if и позволяет избежать кода с огромными отступами. Давайте посмотрим, как использовать оператор if-elif для решения реальной за­ дачи. Реальная ситуация: в компании работают люди со всей страны. Отдел кадров классифицирует города по количеству населения на 3 категории: А, В и С. Размер компенсации аренды жилья зависит от класса города по следующим правилам: для города класса А — 30% от базовой заработной платы, для города класса В — 20% от базовой заработной платы, для города класса С — 10% от базовой заработной платы. Базовая зарплата и класс города сотрудника вводятся с клавиатуры. Рассчитайте сумму компенсации, подлежащую выплате сотруднику. Решение: In [7]: name = "Нилаб" basic_salary = int(input("Зарплата сотрудника {) составляет: " .format(name))) city_class = input("{} живет в городе класса: ".format(name)) if city_class == ("a" or "A"): HRA = (basic_salary * 30)/100 elif city_class == ("b" or "B"): HRA = (basic_salary * 20)/100 elif city_class == ("c" or "C"): HRA = (basic_salary * 10)/100 print("Компенсация за аренду жилья для {} составит: {}" .format(name, HRA)) Зарплата сотрудника Нилаба составляет: 100 000 Нилаб живет в городе класса: b Компенсация за аренду жилья для Нилаба составит: 20000.0 У операторов elif и else должно быть двоеточие в конце логической строки, а по­ сле него следует соответствующий блок операторов (разумеется, с правильным от-
142 | Глава 5 ступом). Оператор if можно использовать внутри блока if другого оператора if — это называется вложенный оператор if1. 5.3. Оператор цикла for Циклы в программировании используются для многократного выполнения опреде­ ленного блока кода. Цикл for в Python выполняет итерацию по элементам передан­ ной последовательности (списка или строки) в том порядке, в котором они в этой последовательности представлены (рис. 5.5). (Термин «итерация» означает повто­ рение процесса.) In [8]: # работа со списком строк words = ['cat', 'window', 'defenestrate'] for w in words: print(w, len(w)) cat 3 window 6 defenestrate 12 В данном операторе for переменная w— это просто обозначение, не связанное с конкретной буквой алфавита. Эта переменная может иметь любое имя. Тот же при­ мер с обозначением i: In [9]: # Работа со строками: words = ['cat', 'window', 'defenestrate'] for i in words: print(i, len(i)) cat 3 window 6 defenestrate 12 1 Swaroop, 2003 (https://python.swaroopch.com/) [39].
Операторы управления потоком | 143 Нельзя не отметить простоту оператора for. Мы указываем переменную, которую хотим использовать (w или i в приведенных примерах), а затем используем опера­ тор in, чтобы связать переменную с последовательностью, которую мы хотим пере­ брать (здесь words — это наш список, т. е. последовательность). Обобщенно синтаксис выглядит следующим образом: for переменная in последовательность: код блок for Этот синтаксис похож на описание на английском языке и переводится как «для [каждого] значения в списке». Это одна из тех синтаксических конструкций, кото­ рые приближают Python к разговорному языку. 5 .3.1. Цикл fore блоком else В цикле for также может быть необязательный блок else. Блок else выполняется, когда элементы в последовательности, перебираемой циклом for, заканчиваются (рис. 5.6). Рис. 5.6. Цикл for с блоком else Приведенный простой пример поможет вам понять принцип работы цикла с блоком else. In [10]: numbers = [1, 2, 3, 4, 5) for i in numbers: print (i) else: print("this is end of the code!") 1 2 3 4 5 this is end of the code! for
144 | Глава 5 5.4. Функция range()] Если вам необходимо перебрать простую последовательность чисел, поможет встроенная функция range (). Она генерирует арифметическую прогрессию. In [11]: for i in range(5): print(i) о 1 2 3 4 При этом последняя точка никогда не является частью сгенерированной последова­ тельности, например функция range (10) генерирует 10 значений, представляющих собой допустимые индексы элементов последовательности длиной 10. Диапазон может начинаться с любого числа или иметь произвольный шаг (даже отрицатель­ ный), если это указать явно в параметрах функции: range(5, 10) 5, 6, 7, 8, 9 range(0, 10, 3) 0, 3, 6, range (-10, -100, -30) -10, -40, -70 Для перебора элементов последовательности можно комбинировать функции range() И 1еп(). In [12]: а= ['Mary', 'had', 'a', 'little', 'lamb'] for i in range(len(a)): print(i, a[i]) 0 Магу 1 had 2 а 3 little 4 lamb Если вы просто выводите диапазон, вывод получается странным. In [13]: print (range (10)) [range(0, 10) Как мы видим здесь, функция range () сама по себе не возвращает того, что мы ожи­ дали получить. Так что же здесь изменилось? 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Операторы управления потоком | 145 И вот тут нам пора ввести понятие итераторов. Зачастую объект, возвращаемый функцией range (), ведет себя очень похоже на спи­ сок, но это не так. Это объект, который поочередно возвращает элементы переданной ему последова­ тельности, когда вы перебираете его, но при этом сам список не создается, экономя память. Подобрые объекты называются итерируемыми, т. е. их можно обрабатывать с по­ мощью функций и конструкций, которые ожидают получить тип данных, у которо­ го можно перебрать элементы, пока они не закончатся. Мы видели, что оператор for именно так и работает. Есть еще одна функция которая создает списки из итерируемого объекта. In [14]: |Out[14J: list о, list (range (5)) To, 1, 2, 3, 4] В следующих главах мы рассмотрим больше функций, которые возвращают ите­ рируемые объекты и принимают их в качестве аргумента. 5.5. Цикл while Цикл while используется для перебора блока кода, пока выполняется заданное условие (рис. 5.7). Цикл while обычно используется в тех случаях, когда мы не знаем, сколько раз придется выполнить цикл. In [15]: п = 10 # присвоение значений переменным sum = 0 i = 1 while i <= n: sum = sum + i i = i + 1 # обновление счетчика
146 | Глава 5 print("The sum is", sum) |The sum is 55 В приведенном примере цикл будет выполняться до тех пор, пока условие while возвращает True. Когда цикл закончится, программа перейдет к следующему выра­ жению — print(). Значение переменной счетчика необходимо увеличивать в теле цикла. Это очень важно (и об этом часто забывают). В противном случае возникнет бесконечный цикл. Подобно циклу for, у цикла while тоже может быть блок else, и используется он таким же образом. 5.6. Операторы break и continue 5.6.1. Оператор break' Оператор break прерывает выполнение самого внутреннего цикла for или while. Операторы цикла могут иметь блок else, который выполняется, когда цикл завер­ шается, перебрав все элементы (в случае цикла for) или когда условие становится ложным (в случае цикла while). Обратите внимание, что блок else не выполняется, когда цикл завершается оператором break (рис. 5.8). Для лучшего сравнения рассмотрим тот же пример с оператором else. Но на этот раз в цикле for используем оператор break. Обратите внимание, как меняется результат. In [16]: numbers = [1, 2, 3, 4, 5] for i in numbers: print(i) break else: print("this is end of the code!") print("this line is outside the loop") T this line is outside the loop Вы заметили, что вместо 5 строк вывода, которые ранее печатал тот же цикл без оператора break, теперь выводится только одна строка в цикле? Дело в том, что оператор break остановил цикл for и не перевел его на следующую итерацию и про­ пустил блок else. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Операторы управления потоком | 147 Рис. 5.8. Блок-схема циклов for (слева) и while (справа) с оператором break Разберем еще один пример, который позволит лучше понять циклы и операторы На этот раз рассмотрим вложенный цикл. У нас будут внешний и вложенный циклы. break. В качестве примера возьмем цикл, который ищет простые числа: In [17]: for n in range(2, 10): for x in range(2, n): if n % x == 0: print(n, 'equals', x, n//x) break else: # цикл прерывается, не найдя делителя print(n, 2 'is a prime number') is a prime number 3 is a prime number 4 equals 2*2 5 is a prime number 6 equals 2*3 7 is a prime number 8 equals 2*4 9 equals 3*3 Присмотритесь внимательно: здесь блок else относится к циклу for, а не к опера­ тору if.
148 | Глава 5 В этом примере много интересного. Я рекомендую вам запустить этот код на своем компьютере, попробовать разные вариаты реализации и проанализировать резуль­ таты. 1. Что произойдет, если оператор else станет частью блока оператора if? 2. Что произойдет, если оператор else станет частью внешнего цикла for? 3. Попробуйте все перечисленные варианты с оператором break и без него и по­ смотрите, что у вас получится. В чем будет отличие от первого варианта? 5.6.2. Оператор continue Оператор continue используется для пропуска части кода внутри цикла в пределах текущей итерации (рис. 5.9). Цикл не завершается, а сразу перейдет на следующую итерацию1. Рис. 5.9. Блок-схема оператора continue продолжает выполнение кода со следующей итерации цикла: Оператор continue In [18]: for alphabet in "python": if alphabet == "t": continue print(alphabet) print("The end") 1 Programiz, 2020 (https://www.programiz.com/Python-programming/break-continue) [18].
Операторы управления потоком | 149 Р у h о п The end Вы заметили, что буква t в слове Python не вывелась на экран? Рассмотрим еще один пример: In [19]: for num in range(2, 10): if num % 2 == 0: # четное число print("Found an even number", num) continue print("Found a number", num) Found an even number 2 Found a number 3 Found an even number 4 Found a number 5 Found an even number 6 Found a number 7 Found an even number 8 Found a number 9 Вы можете заметить, что результаты получились такими же, как если бы мы ис­ пользовали блоки if-else. In [20]: for num in range(2, 10): if num % 2 == 0: # четное число print("Found an even number", num) else: print("Found a number", num) Found an even number 2 Found a number 3 Found an even number 4 Found a number 5 Found an even number 6 Found a number 7 Found an even number 8 Found a number 9 5.7. Оператор pass1 Оператор pass ничего не делает. Его можно использовать, когда в данном месте программы оператор синтаксически требуется, но никаких действий в этом месте выполнять не нужно. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
150 Гпава 5 | Обычно он используется для создания минимальных классов: In [21]: class MyEmptyClass: pass Еще его можно использовать в качестве заполнителя для функции или тела условия в момент написания нового кода. Это позволяет сначала набросать шаблон кода на более абстрактном уровне. Интерпретатором этот оператор просто игнорируется: In [22]: def initlog(*args): pass # не забудьте реализовать это! 5.8. Резюме В этой главе мы изучили очень интересные концепции того, как можно управлять потоком кода. Без операторов if или циклов код может выполняться только сверху вниз, построчно и в неизменном порядке. Именно эти инструменты облегчают ра­ боту программиста, а также позволяют ему делать сложные вещи. Область дейст­ вия оператора if по умолчанию включает в себя блок кода, следующий за операто­ ром if и записанный с отступом. Если вы хотите выполнить более одного выраже­ ния, у всех строк должен быть одинаковый отступ после оператора if. Блок if может иметь, а может и не иметь блок else. В Python существуют два типа циклов: for и while. Оператор break прерывает выполнение цикла. Оператор continue пропус­ кает выполнение следующих за ним выражений в цикле и начинает новую итера­ цию цикла. Мы рассмотрели, как прервать цикл и как продолжить выполнять его без завершения. Рассмотренные операторы и циклы необходимы для базового понимания логики программирования. 5.9. Упражнения 5.9.1. Ответьте на вопросы 1. Каков порядок выполнения выражений в программе Python? Как его изменить? 2. Что делают приведенные фрагменты кода? а) а = 50 if а >= 100: print("Value of a is {}".format(а)) б) a = 90 if a <= 100: print("Value of a is {}".format(a)) в) x = 50 if x >= 10: print("Value of x is {}".format(x)) else: print("Value of x is less than 10")
Операторы управления потоком г) | 151 х = 5 if х >= 10: print("Value of x is {(".format(x)) else: print("Value of x is less than 10") Д) x = 0 while x < 5: print(x) x += 1 e) for i in range(5, 25, 5): print(i) 3. Есть ли ошибки в приведенных фрагментах? Если да, то какие, а) а = 12 if а == 10 print("a is equal to 10") б) а = 90, b = 15 if а <= 100: print("Value of a is less than 100") B) x = 22 if x >= 10: print("x is bigger than 10") else print("x is less than 10") r) x = 5 if x >= 10: print("Value of x is {}".format(x)) else x < 10: print("Value of x is less than 10") Д) x = 5 if x > 10: print("Value of x is more than 10) else: print("Value of x is less than 10") elif x == 10: print("Value of x is equal to 10") e) x = o while x < 5 print(x) x =+ 1 5.9.2. Правда или ложь 1. Когда оператор в коде. if имеет значение True, он выполняет лишь одну инструкцию
152 | Гпава 5 2. Блок кода сразу после оператора условие возвращает True. 3. Оператор else 4. Оператор строке. elif 5. Оператор else while это блок if, 10. Оператор if. представляет собой комбинацию операторов также может использоваться с циклом for else и if в одной for. должен быть объектом-итератором. выполняет блок кода, пока выполняется условие. 8. Оператор break прерывает самый внутренний цикл 9. Оператор который выполняется, когда обязательно есть после каждого оператора 6. Объект в теле цикла 7. Цикл if — continue pass for. используется для пропуска всех оставшихся итераций цикла. ничего не делает. 5.9.3. Практические задания 1. Трейдер хочет, чтобы программа проверяла, получил ли он прибыль или убы­ ток по сделке. Напишите программу, в которой с клавиатуры вводится цена по­ купки и продажи, а в ответ программа сообщает, получил ли трейдер прибыль или убыток. Программа также должна рассчитать сумму прибыли или убытка. 2. Напишите программу, которая проверяет, является ли год, введенный с клавиа­ туры, високосным. 3. Трое сотрудников, Самир, Правин и Мохит, вводят свой опыт работы с клавиа­ туры. Напишите программу, которая определяет наиболее и наименее опытного из них. 4. Сумма трех углов треугольника составляет 180°. Напишите программу, которая проверяет, является ли фигура треугольником, если в качестве входных данных вводятся три угла. 5. Даны три угла треугольника. Напишите программу, которая проверит, является ли он прямоугольным (один из углов должен составлять 90°). 6. Сколько разных трехзначных чисел можно получить, используя цифры 1, 2 и 3 в разных позициях? Напишите программу для генерации всех таких чисел (под­ сказка: используйте цикл for). 7. Напишите код для вывода таблицы умножения любого заданного числа. 8. Напишите программу для вывода всех простых чисел от 1 до 500. 9. Выведите все числа, кратные 9, которые меньше 300 (подсказка: вы можете ис­ пользовать функцию range о). 10. Машина в течение срока службы приносит годовой доход в размере 200 000 руб. Сама она стоит 1 000 000 руб. в момент покупки и продается за 250 000 руб. при утилизации. Вложив ту же сумму в другие инвестиционные инструменты, можно заработать 8 % годовых. Каков минимальный срок службы машины, при котором она станет более привлекательной по сравнению с альтернативными инвестициями?
6 Функции Функции делают программы более простыми и легко читаемыми. Если говорить простым языком, функция представляет собой именованный блок кода, который запускается только при вызове. Это слишком простое объяснение, но зато верное. Функции помогают программисту избегать повторного написания одного и того же кода. 6.1. Определение функций Первый вопрос, на который нам нужно ответить: что такое функция^ В Python функция — это группа связанных операторов, выполняющих определен­ ную задачу1. С помощью функций можно разбить программу на более мелкие части. По мере того как наша программа становится все больше и больше, функции становятся все более и более необходимы для поддержания организованности и управляемости кода. Как и все остальное в Python, функции тоже являются объектами. В функцию можно передавать данные, называемые параметрами. Функция может возвращать данные как результат своей работы. Чтобы вызвать функцию, нужно указать имя функции, за которым следуют круглые скобки о с параметрами. На­ пример, функция 1еп(х) возвращает длину параметра х. 6.2. Типы функций Функции бывают двух типов. ♦ Встроенные функции уже определены в Python и могут быть вызваны напря­ мую. ♦ Пользовательские функции — это объекты, которые создаются пользователем с помощью явного определения. Функция вызывается с тем же количеством ар­ гументов, что и в формальном описании функции. 1 Programiz, 2020 (https://www.programiz.com/Python-programming/break-continue) [18].
154 | Гпава 6 В дальнейшем, говоря об определении функций, мы будем иметь в виду именно пользовательские функции. 6.3. Встроенные функции' У интерпретатора Python есть несколько встроенных функций. Они перечислены в табл. 6.1 в алфавитном порядке. Мы уже видели и использовали некоторые из них, например 1еп() И т. д. print (), int (), input (), ТАБЛИЦА 6.1 Встроенные функции abs () delattr() hash() memoryview() set!) all() diet() help() min!) setattr() any() dir() hex!) next() slice!) ascii () divmod() id!) object!) sorted!) bind enumerate() input () oct!) staticmethod!) str!) boolO eval() into open() breakpoint() exec() isinstance!) ord!) sum!) bytearray() filter!) issubclass!) pow() super() bytes() float() iter!) print() tuple() callable 0 format() lend property() type!) chr() frozenset () list!) range() vars() classmethod () getattr() locals!) reprd zip!) compile() globals() map!) reversed() _ import__() complex() hasattr() max () round() 6.3.1. Описание некоторых встроенных функций В Python есть встроенные функции, которые мы будем использовать чаще других. Давайте рассмотрим определения некоторых из них. В круглых скобках указываются объекты, который нужно передать функции в ка­ честве аргумента. ♦ аЬз(х) возвращает абсолютное значение числа. Аргумент может быть целым числом или числом с плавающей точкой. Если аргумент — комплексное число, возвращается его абсолютное значение. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Функции | 155 ♦ any(iterabie) возвращает True, если какой-либо элемент переданной последова­ тельности истинен. Если итерируемый объект пуст, возвращается False. ♦ chr(i) возвращает строку, представляющую собой символ, кодировка которого в таблице Unicode равна 1. Например, chr(97) возвращает строку 'a', a chr(8364) воз! >ащает строку Функция обратна функции ord(). ♦ dir ([object]) при вызове без аргумента возвращает список имен всех локальных объектов. С аргументом возвращает список допустимых атрибутов для передан­ ного объекта. ♦ float ([х]) возвращает число с плавающей точкой, полученное из числа или строки X. ♦ help ([object]) — это вызов встроенной справочной системы (эта функция пред­ назначена для интерактивного использования). При вызове без аргумента на консоли интерпретатора запускается интерактивная справочная система. Если аргумент является строкой, то ищется соответствующее имя модуля, функции, класса, метода, ключевого слова или раздела документации, а на консоли выво­ дится страница справки. Если аргумент является объектом любого другого типа, для этого объекта создается справочная страница. ♦ id (object) возвращает идентификатор объекта. Это целое число, которое гаран­ тированно будет уникальным и постоянным для этого объекта в течение всего его времени жизни. Два объекта с неперекрывающимся временем жизни могут иметь одинаковое значение id (). С точки зрения реализации CPython это адрес объекта в памяти. ♦ input([prompt]) используется для получения ввода от пользователя. Если передан аргумент, он выводится в стандартный поток вывода без символа новой строки в конце. ♦ int ([х]) возвращает целочисленный объект, сформированный из числа или стро­ ки X. ♦ isinstance(object, classinfo) возвращает True, если аргумент object является эк­ земпляром класса classinfo или его подклассом (прямым, косвенным или вирту­ альным). Если объект не является объектом данного типа, функция возвращает False. ♦ ien(s) возвращает длину (количество элементов) переданного объекта. В качест­ ве аргумента можно передать последовательность (например, строку, байтовую строку, кортеж, список или диапазон) или коллекцию (словарь, множество или замороженное множество). ♦ map (function, iterabie[, ...]) возвращает итератор, который применяет передан­ ную функцию к каждому элементу переданного итерируемого объекта. Если в функцию тар о передается несколько итерируемых аргументов, то указанная функция function () должна принимать такое же количество аргументов и будет применяться к элементам из всех итерируемых аргументов параллельно. При этом итератор остановится, когда дойдет до конца самого короткого из итери­ руемых объектов.
156 | Гпава 6 *args[, key]) возвращает наибольший элемент в итерируемом объекте или наибольший из переданных аргументов. ♦ max(argi, arg2, ♦ min (argi, arg2, *args[, key]) возвращает наименьший элемент в итерируемом объекте или наименьший из переданных аргументов. ♦ open (file) открывает файл и возвращает соответствующий файловый объект. ♦ ord (с) принимает строку, состоящую из одного символа Unicode, и возвращает целое число, представляющее код Unicode этого символа. Например, ord('a') возвращает 97, a ord('€') возвращает 8364. Функция обратна chr (). ♦ print(‘objects, sep=' егк^'\п', file=sys. stdout, flush=False) ВЫВОДИТ объекты в текстовый поток с разделителями sep и окончанием end. Аргументы sep, end, file и flush, если они есть, должны быть указаны как именованные аргументы. Все неименованные аргументы преобразуются в строки функцией str о и запи­ сываются в поток с разделителем sep и окончанием end. И sep, и end должны быть строками. Они могут иметь значение None, в результате чего будут использовать­ ся значения по умолчанию. Без аргументов функция print () просто выводит пус­ тую строку. ♦ repr (objects) возвращает строку, содержащую формальное строковое представ­ ление объекта. ♦ reversed(seq) возвращает итератор в обратном порядке. ♦ round (number [, ndigits]) округляет число с точностью до ndigits знаков после де- сятичной точки. Если аргумент ndigits опущен или равен None, функция возвра­ щает ближайшее целое. ♦ sorted (iterable, *, key=None, reverse=False) возвращает НОВЫЙ отсортированный список из элементов переданного итерируемого. ♦ type (object) принимает один аргумент и возвращает его тип. 6.4. Пользовательские функции Это один из самых мощных инструментов большинства языков программирования, который позволяет пользователю писать свои собственные функции. Это дает без­ граничные возможности для создания повторно используемого кода для выполне­ ния повторяющихся задач. Встроенных функций не так много. Когда программисту нужен функционал, кото­ рого нет во встроенной библиотеке, он создает его сам. Так и появляются пользо­ вательские функции. Чтобы лучше понять эту тему, давайте создадим нашу собственную функцию. 6.4.1. Зачем создавать функции? Возникает естественный вопрос: а зачем вообще писать отдельные функции? Почему бы не объединить всю логику в один код? Дадим парочку пояснений.
Функции | 157 ♦ Создавая свои функции, программист избавляется от необходимости переписы­ вать один и тот же код снова и снова. Предположим, что в вашей программе есть фрагмент кода, который вычисляет процентную ставку. Если вы захотите рас­ считать процентную ставку для другой основной суммы и для другого периода времени в той же программе, вам явно не доставит удовольствия заново писать один и тот же код. Вместо этого вы бы предпочли повторить выполнение фраг­ мента кода, который вычисляет проценты, а затем вернуться к тому месту, где вы остановились. Этот фрагмент кода — не что иное, как функция. ♦ Лучше разбивать разные действия на отдельные функции, чем писать всю логи­ ку в одном месте. Так у программы будет модульная структура. Более мелкие функции могут повторно пригодиться в аналогичных ситуациях. А если вся ло­ гика объединена в одной крупной функции, вы не сможете повторно использо­ вать какую-то ее часть, придется написать еще один фрагмент кода. ♦ Разделение кода на функции упрощает разработку и понимание программы. Также, если работа программы может быть разделена на отдельные действия и каждое действие помещено в отдельную функцию, вы можете писать и прове­ рять фрагменты кода независимо друг от друга. 6.4.2. Создание и вызов функций Как и у всего остального, у создания (определения) функций есть собственный син­ таксис. Он весьма прост: def нмя_функции(') : тело_функцми Когда мы пишем оператор def, интерпретатор Python понимает, что мы собираемся определить функцию. Совершенно очевидно, что «def» — это сокращение от англ. define (определять). Теперь мы должны дать нашей функции уникальное имя. По­ сле слова def следует имя функции, затем пара круглых скобок о и двоеточие (:). В следующей строке идет тело функции. Оно начинается с отступа, который сооб­ щает Python, что этот блок кода является телом функции. Тело функции— это не что иное, как код, который функция выполняет. Имя, которое мы даем нашей функции, должно быть уникальным, как и перемен­ ные. Мы можем назвать нашу функцию как угодно, но необходимо при этом соблюдать правила языка Python. Кроме того, функцию следует наделять таким именем, которое связано с ее назначением, т. е. имеет смысл. Это поможет другим программистам, читающим ваш код, легко понять, для чего она предназначена. Давайте определим простую функцию, чтобы быстрее освоить новую концепцию. In [1]: def greeting(): print("Good Morning") Повторите этот код на вашем компьютере и запустите его. Вы получили какой-нибудь результат? Нет, и не должны! Потому что мы лишь определили новую функцию, но не вызывали ее.
158 | Гпава 6 Давайте разберемся с помощью небольшой аналогии. Допустим, я научил вас тан­ цевать. Но чтобы заставить вас танцевать, нужно сказать: «Давай станцуем». Точно так же, определив функцию, мы научили компьютер выполнять некоторые задачи. Но чтобы выполнить эту задачу, нам нужно вызвать функцию. В Python для вызова функции нужно ввести ее имя и пару круглых скобок. Проверим это. In [2]: # вызовем определенную ранее функцию greeting() Good Morning Вам, наверное, интересно, зачем мы написали функцию для задачи, которая реша­ ется с помощью одной строки кода. Дело в том, что это лишь пример простой функции, на которой мы показываем порядок действий. Обычно функции несколь­ ко сложнее. Теперь давайте познакомимся с другими свойствами пользовательских функций. 6.4.3. Входные параметры и аргументы Если вас одолела жажда и вы идете в киоск с напитками, то у вас есть два варианта (рис. 6.1). Вы можете купить лимонад за 50 руб. или, если у вас есть 100 руб., купить Sprite. Рис. 6.1. Пример с напитками Каждая покупка уникальна. Вам нужно сообщить владельцу киоска, какой из двух товаров вам нужен. В зависимости от вашего ответа он продаст вам напиток. Аналогичным образом в программировании в ответ на разные входные данные должны возвращаться разные результаты. В этом нам помогают функции. Давайте смоделируем наш киоск с напитками в виде функции. In [3]: def Lemonade_Stall (): print("Лимонад сделан из:") print("Лимонный сок") print("Вода")
Функции | 159 print("Соль") print("Сахар") print("Sprite сделан из:") print("Лимонный сок") print("Содовая") print("Сахар") print("Секретный ингредиент") Теперь, когда мы вызываем нашу функцию дующим. In [4]: Lemonade stall (), результат будет сле­ Lemonade Stall() Лимонад сделан из: Лимонный сок Вода Соль Сахар Sprite сделан из: Лимонный сок Содовая Сахар Секретный ингредиент 6.4.3.1. Параметры На выходе мы получили оба напитка. А если нам нужен только лимонад за 50 руб., или только Sprite за 100 руб.? Научим нашу функцию понимать разницу. In [5]: def Lemonade_Stall(): if (price == 5): print("Лимонад сделан из:") print("Лимонный сок") print("Вода") print("Соль") print ("Сахар") if (price == 10): print("Sprite сделан из:") print("Лимонный сок") print("Содовая") print("Сахар") print("Секретный ингредиент") else: print("Пожалуйста, заплатите нужную сумму") In [6]: # вызов нашей функции Lemonade Stall()
160 Главаб | Traceback (most recent call last) NameError <ipython-input-6-149842be07ba> in <module> 1 # вызов нашей функции --- > 2 Lemonade_Stall() <ipython-input-5-d9c3cdcb52a5> in Lemonade_Stall() 2 3 def Lemonade_Stall(): --- > 4 5 6 if (price == 5): print("Лимонад сделан из:") print("Лимонный сок ") NameError: name 'price' is not defined Что пошло не так? Если вы прочитали описание ошибки, то уже знаете ответ. Здесь в функции мы ис­ пользовали переменную price, которая нигде не определена. Python не знает, что делать с этой переменной, отсюда и ошибка. Эту ошибку я ввел намеренно, чтобы подчеркнуть важность параметров. Давайте исправим код и запустим его еще раз. In [7]: # обратите внимание на переменную price после имени функции в () def Lemonade_Stall(price): if (price == 5): print("Лимонад сделан из:") print("Лимонный сок") print("Вода") print("Соль") print("Сахар") if (price == 10): print("Sprite сделан из:") print("Лимонный сок") print("Содовая") print("Сахар") print("Секретный ингредиент") else: print("Пожалуйста, заплатите нужную сумму") Переменная price, которая указана в круглых скобках в определении функции, называется параметром функции. 6.4.3.2. Аргументы Давайте вызовем функцию, которую мы только что определили выше, и оценим результат. In [8]: Lemonade_Stall()
Функции I 161 Traceback (most recent call last) TypeError <ipython-input-8-54701b5c8c30> in <module> --- > 1 Lemonade_Stall() TypeError: Lemonade Stall() missing 1 required positional argument: 'price' Упс... а теперь что пошло не так? Ошибка уже другая. Вы заметите, что в сообщении об ошибке интерпретатор все еще ругается на нашу переменную price, но на этот раз по другому поводу. Там сказано, что пропущен один позиционный аргумент. Аргумент — это значение, которое мы присваиваем параметру при вызове функ­ ции. Вызываемая нами функция запуталась, т. к. у функции есть параметр, но мы не задали для него значение при вызове функции. Давайте снова вызовем нашу функцию, но на этот раз с аргументом. In [9]: Lemonade_Stall(50) Лимонад сделан из: Лимонный сок Вода Соль Сахар In [10]: # и снова, на этот раз с другим аргументом Lemonade_Stall(80) Пожалуйста, заплатите нужную сумму Теперь самостоятельно вызовите функцию ве аргумента число 100. Lemonade_stall () и передайте ей в качест­ * * * Теперь наша функция знает, кому и что подавать. Вы успешно определили свою первую функцию с параметром. Итак, повторим определения параметра и аргумента. Параметр — это переменная, указанная в скобках в определении функции: def имя_функции(параметр) : тело_ функции А аргумент — это значение, которое передается в функцию при ее вызове: имя_функции (аргумент) 6.4.3.3. Количество аргументов Когда вы вызываете функцию, ей нужно передать правильное количество аргумен­ тов. То есть если у функции определены 2 параметра, вы должны передать ей 2 аргумента, не больше и не меньше.
162 | In [11]: Главаб def my_name(first_name, last_name): print(first_name, last_name) In [12]: my_name("Nilabh", "Nishchhal") |Nilabh Nishchhal Попробуйте вызвать указанную функцию не с двумя аргументами и проверьте результат. 6.4.4. Возврат значений из функций Мы создали несколько функций. Но эти функции только выводят результат на экран и не возвращают никакого значения. Звучит странно, я знаю. Давайте разберемся с этим на другом примере. Напишем функцию, которая печатает ряд Фибоначчи. In [13]: def fib(n): # вывод ряда Фибоначчи до п а, Ь = 0, 1 while а < п: print(a, end=' ') a, b = b, а + b print() In [14]: # вызовем функцию, которую мы только что определили fib (100) |0 1 1 2 3 5 8 13 21 34 55 89 На первый взгляд кажется, будто функция fib () возвращает нам какие-то значения. Но на самом деле это не так. Она просто выводит их на экран. Возвращаемое значение— это не то значение, которое выводится на экран. По­ скольку определение функции не содержит оператора return, функция возвращает значение None. Вывод на экран значения None обычно игнорируется интерпретато­ ром, если это единственное выводимое значение. Это легко продемонстрировать с помощью функции print (). In [15]: print(fib(100)) 0 1 1 2 3 5 8 13 21 34 55 89 None Как вы могли заметить, наша функция fib () сейчас ничего не возвращает. Она про­ сто печатает числа. Разница станет яснее, если мы создадим другую функцию список чисел Фибоначчи. fib2(), которая вернет Для этого мы просто изменим функцию, чтобы она возвращала список чисел ряда Фибоначчи, а не печатала его.
Функции In [16]: def fib2(n): I 163 # возврат ряда Фибоначчи до n result = [] a, b = О, 1 while a < n: result.append(a) # добавляет число в список a, b = b, а + b return result In [17]: |Out[17]; fib2(100) # обратите внимание, что список выводится в [] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] Что я имел в виду, когда говорил, что наша функция и не возвращает никакого значения? fib о только выводит на экран Попробуем проделать с обеими функциями некоторые операции. In [18]: fib(20) * 2 # умножение на 2 0112358 13 Traceback (most recent call last) TypeError <ipython-input-18-630c287ba55a> in <module> --- > 1 fib (20) * 2 # умножение на 2 TypeError: unsupported operand type(s) for *: 'NoneType' and 'int' In [19]: fib2(20) * 2 | [0, 1, 1, 2, 3, 5, 8, 13, 0, 1, 1, 2, 3, 5, 8, 13 Вы заметили разницу? Результат функции fib() нельзя использовать в операции умножения, потому что эта функция не возвращает никакого значения, а лишь печатает числа. Эта функция возвращает NoneType, как сказано в сообщении об ошибке. А вот функция fib2 () возвращает список, над которым можно выполнить эту опе­ рацию (здесь оператор умножения не умножает числа, а выполняет слияние спи­ сков, поэтому значения повторяются). В этом примере мы также рассмотрели новые функции Python. ♦ Оператор return возвращает значение из функции. Если после оператора return ничего не указать, возвращается None. Если этот оператор отсутствует в конце функции, тоже возвращается None. ♦ В выражении result, append (а) вызывается метод списка result. Метод— это функция, которая «принадлежит» объекту и определяется типом объекта. Раз­ ные типы объектов имеют разные методы. Метод append!) в нашем примере определен для списков и добавляет новый элемент в конец списка. Это эквива­ лентно выражению result = result + [а], но более эффективно.
164 | Главаб 6.5. Варианты передачи аргументов Вы можете определять функции с переменным количеством аргументов. Мы уже знаем, как определить функцию с одним аргументом. Теперь давайте определим функцию с более чем одним аргументом. Существуют четыре варианта передачи аргументов, которые можно комбиниро­ вать. ♦ Аргументы со значением по умолчанию. ♦ Произвольное число аргументов (*args). ♦ Именованные аргументы. ♦ Произвольное число именованных аргументов (**kwargs). Разберем все эти варианты по очереди, а потом посмотрим, как их можно комбини­ ровать. 6.5.1. Аргументы со значением по умолчанию Наиболее полезный вариант — это указать для одного или нескольких аргументов значение по умолчанию. В этом случае функцию можно вызвать с меньшим коли­ чеством аргументов, чем в ней определено. Например: In [20]: def my_address(city, state, country = "India"): print("I live in", city, In [21]: state, country) my_address("Mumbai", "Maharashtra") |I live in Mumbai , Maharashtra , India Значение по умолчанию не означает, что это единственное значение, которое мо­ жет принимать данный параметр. Вы можете передать в функцию любое другое значение. То есть если при вызове функции вы не указываете для этого аргумента значение, он принимает значение по умолчанию. Давайте рассмотрим это на при­ мере с другим адресом. In [22]: my_address("Sydney", "New South Wales", "Australia") 11 live in Sydney , New South Wales , Australia 6.5.2. Произвольное число аргументов (*args) Если вы не знаете, сколько аргументов будет передано в вашу функцию, добавьте перед именем параметра в определении функции символ *. Таким образом, функция получит кортеж аргументов и сможет соответственно обращаться к элементам кортежа. In [23]: def fruit_basket(*fruit): print(fruit) In [24]: fruit_basket("apple", "grapes", "strawberry") [('apple', 'grapes', 'strawberry')
Функции | 165 Не все аргументы, которые мы передаем, должны выводиться. Это полностью зави­ сит от определения функции. In [25]: def todays_fruit(*fruit): print(fruit[1]) # только второй "фрукт" в кортеже In [26]: todays_fruit("apple", "grapes", "strawberry") |grapes ~ Под переменным числом аргументов подразумевается количество от нуля и боль­ ше. В документации Python произвольное число аргументов часто обозначается как *args. In [27]: def write_multiple_items(file, separator, *args): file.write(separator.j oin(args)) 6.5.3. Именованные аргументы1 В рассмотренных примерах мы видели, что порядок аргументов имеет значение. В Python порядок аргументов при вызове функции должен быть такой же, как у параметров в определении функции. Аргументы также можно передавать с использованием синтаксиса В этом случае порядок аргументов не будет иметь значения. key = value. Следующий пример поможет вам все понять. Определенная ниже функция принимает один обязательный аргумент и три дополнительных именованных аргумента (state, action и type). In [28]: (voltage) # скетч из Монти Пайтона про мертвого попугая и вариации def parrot(volt, state='мертв', act='оживет', type='Норвежский голубой'): print("- Этот попугай не", act, end=' ') print("даже если пропустить", volt, "вольт через него.") print ("- Какое оперение!", type) print("- Он", state, "!") Эту функцию можно вызвать любым из следующих способов: parrot (1000) # первый позиционный аргумент parrot(volt=1000) # первый именованный аргумент parrot(volt=1000000, act='полетит') # два именованных аргумента parrot(act='полетит', volt=1000000) # два именованных аргумента parrot('миллион', 'отправился к праотцам', parrot('тысячу', state='летает с ангелами') 'прыгнет') # три позиционных аргумента # один позиционный, # один именованный 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
166 Гпава 6 | А приведенные далее вызовы некорректны: # отсутствует обязательный аргумент parrot() parrot(volt=5.О, 'скончался') # неименованный аргумент после именованного parrot(110, volt=220) # повторяющееся значение одного и того же аргумента parrot(actor='Джон Клиз') # неизвестный именованный аргумент Попробуйте вызвать функцию parrot () на вашем компьютере всеми описанными выше способами и проанализируйте результаты. При вызове функции именованные аргументы должны следовать за позиционными аргументами. Все передаваемые именованные аргументы должны соответствовать одному из параметров, принимаемых функцией (например, actor не входит в число параметров функции parrot ()), а их порядок не важен. Это же относится к обяза­ тельным параметрам (например, вызов parrot (volt=1000) тоже допустим). Ни один аргумент не может принимать значение более одного раза. Вот пример, который из-за этого последнего ограничения не будет работать: In [29]: def function (а): pass In [30]: function(0, a=0) Traceback (most recent call last) TypeError <ipython-input-30-34e44d693230> in <module> --- > 1 function(0, a=0) TypeError: function() got multiple values for argument 'a' 6.5.4. Произвольное число именованных аргументов (**kwargs) Если количество именованных аргументов, передаваемых в вашу функцию, неиз­ вестно, вы можете добавить перед именем параметра в определении функции две звездочки **. В этом случае ваша функция получит словарь аргументов, из которого сможет получить доступ к его элементам по именам. In [31]: def try_function(*args, **kwargs): print ("args: ", args) print("kwargs: ", kwargs) In [32]: try_function("Monday", "Tuesday", "Wednesday", fourth = "Thursday", fifth = "Friday", weekendl = "Saturday", weekend2 = "Sunday") args: ('Monday', 'Tuesday', kwargs: ('fourth': 'Sunday'} 'Wednesday') 'Thursday', 'fifth': 'Friday', 'weekendl': 'Saturday', 'weekend2':
Функции | 167 6.6. Генераторы Генератор— это функция, возвращающая итератор. То есть эти функции генери­ руют объект, который можно перебирать в цикле. Генератор — это особый класс функций. Вместо того, чтобы возвращать одно зна­ чение, функция-генератор возвращает последовательность значений (объектитератор). Слово return в таких функциях заменяется на yield. Рассмотрим это под­ робнее. 6.6.1. Определение генератора Определение функции-генератора выглядит так же, как и у любой другой функции. Единственное отличие состоит в том, что оператор return заменяется оператором yield. Если функция содержит хотя бы один оператор yield (а при этом она может содержать несколько yield или return), она становится функцией-генератором. Раз­ ница между return и yield заключается в том, что оператор return полностью завер­ шает функцию, а оператор yield приостанавливает выполнение функции и сохраня­ ет все ее локальные переменные, а затем продолжает выполнение с того же места при последующем вызове или итерации. Рассмотрим пример. В нем я введу много важных концепций, некоторые из кото­ рых вы еще не встречали. Объясню их после примера. Не пугайтесь новых понятий, поскольку мы разберем их подробнее в следующих главах, и вы сможете вернуться к этому примеру снова, чтобы лучше разобраться. Нам уже известна функция range (). Она возвращает диапазон, не включая значение самого аргумента. Мы создадим пользовательскую функцию-генератор, которая работает точно так же, как и ranged, но диапазон, который она будет возвращать, будет содержать в себе значение аргумента. In [33]: def inclusive_range(*args): numargs = len(args) start = 0 step = 1 # проверка параметров if numargs < 1: raise TypeError("Expected at least one argument, got {}". format(numargs)) elif numargs == 1: stop = args[0] elif numargs == 2: (start, stop) = args elif numargs == 3: (start, stop, step) = args else: raise TypeError("Expected at most 3 arguments, got {}". format(numargs))
168 | Главаб # генератор i = start while i <= stop: yield i i += step Вызов функции генератора возвращает объект, который является объектомгенератором или итерируемым объектом. In [34]: |Out[34]: inclusive_range() <generator object inclusive range at 0x000001ED088F8AC8> Перебрать объект-генератор можно с помощью цикла In [35]: for. for i in inclusive_range(25): print(i, end=" ") |0 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 6.6.2. Пояснение к примеру Начнем со стандартного оператора def, который мы уже использовали в пользова­ тельских функциях. Затем мы указали, что функция inclusive_range () имеет произ­ вольное количество аргументов, т. к. количество аргументов может меняться. Затем мы присвоили значения по умолчанию двум необязательным аргументам start и step, так что, если указан только один аргумент, для них будут использоваться значения по умолчанию. Далее мы выполняем обработку ошибок и исключений. Мы узнаем об этом под­ робно в главе 12. По сути, если передан лишь один аргумент, это должен быть stop. Сообщение об ошибке становится понятным, если передано меньшее или большее количество аргументов, чем требуется. Наконец, последние 4 строки, самый маленький блок кода — это непосредственно функция-генератор. Обратите внимание на использование yield вместо оператора return. 6.7. Резюме Функции делают программирование по-настоящему увлекательным. Это мощней­ шее оружие в руках программиста в любом языке программирования. В этой главе мы узнали о встроенных функциях и рассмотрели самые полезные из них, включая их определения. Мы также увидели, как определять и вызывать собственные функ­ ции. Затем мы продвинулись чуть дальше и увидели, что происходит внутри функ­ ции, что такое параметры и аргументы. Мы узнали, как можно более эффективно использовать разные аргументы для вызова функции. Вооружившись этим инстру­ ментом, обязательно применяйте его в своей работе.
Функции | 169 6.8. Упражнения 6.8.1. Ответьте на вопросы 1. В чем различие между функцией и методом? 2. Как создание своих функций помогает программисту в работе? 3. Чем ограничено тело функции? 4. Можно ли использовать функцию, находящуюся внутри модуля, за пределами модуля? 5. В чем сходство и различие параметров и аргументов функции? 6. Зачем в определении функции нужен оператор return? Что вернет функция, если в ее определении нет оператора return? 7. Как обозначается произвольное количество аргументов? Когда они использу­ ются? 8. Что такое функция-генератор? Чем она отличается от обычных функций? 9. В чем разница между args и kwargs? Что это такое? 6.8.2. Правда или ложь 1. Чтобы вернуть значение из функции, нужно использовать оператор return. 2. Каждый оператор return в функции может возвращать свое значение. 3. Функция обязательно должна возвращать какое-то значение. 4. Функция, которая не возвращает никакого значения, возвращает None. 5. При определении функции нужно указать хотя бы один параметр. 6. Имя *args — это всего лишь соглашение. Вместо args можно использовать любое другое имя. 7. Функция, которая выводит значения на экран, аналогична функции, возвра­ щающей эти значения. 8. Различные виды аргументов в одной функции определять нельзя. 9. При использовании именованных аргументов их порядок не имеет значения. 10. В функции-генераторе нужно использовать оператор yield вместо оператора return. 6.8.3. Практические задания 1. Напишите функцию, которая проверяет, является ли год високосным. 2. Напишите функцию f (х), возвращающую простые множители любого числа (пример простых множителей: 36— [2 2 3 3], 30— [2 3 5]). х
170 | Гпава 6 3. Напишите функцию для преобразования температуры из градусов Цельсия в градусы Фаренгейта. Напишите еще одну функцию для обратного преобразо­ вания. 4. Напишите функцию для вычисления факториала любого числа. 5. Напишите функцию преобразования любого числа от 1 до 100 в римское число. 6. Напишите функцию f (х), которая возвращает таблицу умножения числа х. 7. Напишите функцию, которая принимает в качестве входных данных список и возвращает его перевернутый вариант. 8. Напишите функцию для расчета сложных процентов. 9. Напишите функцию f (х), где х — любое 6-значное число, а функция возвращает сумму его цифр. 10. Напишите функцию, которая проверяет, является ли переданное число про­ стым. 6.8.4. Изучите самостоятельно 1. Придумайте задачи из реальной жизни, которые, по вашему мнению, можно автоматизировать. Возможно, сейчас вы не знаете, как их автоматизировать, но для начала можно хотя бы составить их список. 2. Какие повторяющиеся задачи вы выполняете на своем компьютере? Составьте список этих задач, а затем подумайте об их автоматизации.
7 ПРОЕКТ 1: Рисунки из символов с помощью циклов и функций 7.1. Рисунки с помощью символа * (звездочка) 7.1.1. Прямоугольный треугольник Давайте я сначала расскажу, что нам нужно получить, чтобы мы могли решить, как это реализовать. Нам нужно вывести на экран 6 рядов звездочек, причем количест­ во звездочек в каждой строке равно номеру строки. Между звездочками вставлен один пробел (рис. 7.1). Рис. 7.1 Итак, рассмотрим порядок действий: 1. Вывести одну звезду. 2. Вывести 2 звезды. 3. Вывести 3 звезды. 4. Вывести 4 звезды. 5. Вывести 5 звезд. 6. Вывести 6 звезд. То же самое в виде простейшего кода: in [1]: print("* ") print("* * ") print!"* * * ") print("* * * *") print!"* ****") print!"* *****•') Результат вывода здесь будет как раз такой, как на рис. 7.1
172 | Глава 7 Мы получили, что хотели. Для этого потребовалось всего 6 строк простого кода с функцией print (). А что, если бы нам была нужна фигура из 50 рядов? Какой смысл учиться про­ граммировать, если мы будем выполнять повторяющуюся работу вручную? Как заставить компьютер работать за нас? Давайте упростим решение задачи с помощью циклов. Подумаем заново: ♦ один цикл будет печатать последовательно 6 рядов; ♦ другой цикл будет печатать сами звездочки в рядах. In [2]: row =6 # количество строк или высота треугольника for i in range(0, row): for j in range)0, i + 1): # цикл для перебора строк # цикл для перебора в диапазоне # от 0 до 1 + номер строки print)"* ", end="") # вывод звездочек в строке print)"") # переход на следующую строку Результат вывода здесь — опять то, что изображено на рис. 7.1. В таком коде вы можете легко изменить количество строк, но чтобы где-то повтор­ но вызвать этот же код для другого значения row, вам придется скопировать его це­ ликом. Не слишком похоже на автоматизацию, не так ли? И тут-то нам на помощь приходят функции. Давайте создадим функцию, которая принимает в качестве аргумента количество строк и выводит треугольник на экран. Самое приятное здесь заключается в том, что тело функции у нас уже есть. Нам осталось лишь обернуть его синтаксисом определения функций, с которым вы уже хорошо знакомы. Назовем эту функцию pattern ? (). In [3]: def pattern_T(n): for row in range(0, n): for stars in range (0, row +1): print)"* ", end="") print("") In [4]: pattern_T(6) Результат вывода здесь — опять см. на рис. 7.1. Мы прошли путь от реализации нашей задачи 6-ю строками кода до определения одной функции и использования ее для любого количества строк любое количество раз. 7.1.2. Перевернутый прямоугольный треугольник Предположим, мы теперь хотим получить перевернутый вариант прямоугольного треугольника (рис. 7.2). Мы снова начнем с самого простого, как и в прошлом примере. Просто напишем 6 строк кода для последовательного вывода 6 строк. Сделаем это лишь для понима­ ния того, как должна выглядеть фигура.
Проект 1: Рисунки из символов с помощью циклов и функций In [5]: print(" *") print(" * *") print(" * * *") print(" * * * *") print(" * * * * *") | 173 print("* * * * * *") Рис. 7.2 Из этого кода ясно, что на этот раз в первой строке будет не только звездочка, но и 10 пробелов. Это число в 2 раза больше количества оставшихся строк (для первой строки это 5). Теперь, когда внешний вид фигуры стал понятен, можно написать цикл. In [6]: row = 6 spaces = (row - 1) * 2 # число пробелов в строке # цикл для перебора строк for i in range(0, row): for j in range(0 , spaces): # сначала вывод пробелов print(" ", end="") for j in range(0, i + 1): # вывод звездочек print)"* ", end="") spaces = spaces - 2 # уменьшаем количество пробелов # для следующей строки на 2 print (”") # переход на следующую строку Результат вывода этого цикла см. на рис. 7.2. Давайте преобразуем все это в функцию. In [7]: def pattern_T_inverse(n) : spaces = (n - 1) * 2 for i in range(0, n): for j in range(0, spaces): print(" ", end="") for j in range(0, i + 1): print("* ", end="") spaces = spaces - 2 print ("") In [8]: pattern_T_inverse (6) Результат вывода этой функции повторять нет смысла (см. рис. 7.2).
174 | Гпава 7 7.1.3. Равносторонний треугольник Теперь рассмотрим задачу с получением фигуры равностороннего треугольника, такой как на рис. 7.3. На этот раз первый шаг из 6 функций print () мы пропустим. Вы уже поняли, как это работает. Но, если вы не можете представить, как должен выглядеть вывод, проделайте это самостоятельно. В данном примере в первой строке 5 пробелов, что равно количеству строк ми­ нус 1. Это похоже на предыдущую задачу, где количество пробелов было вдвое больше. Итак, вы без труда могли бы воспроизвести вывод, используя код преды­ дущего примера. Если бы вы были разработчиком, это была бы хорошая идея. Но поскольку вы все еще изучаете основы, каждый раз, когда вы с нуля набираете код и совершаете ошибки, исправляете их и двигаетесь вперед — вы учитесь. Не упус­ тите эту возможность. Я настоятельно рекомендую вам ввести код самостоятельно еще раз, не глядя на предыдущие примеры. Я сделаю то же самое. In [9]: row = 6 spaces = row - 1 for i in range(0, row): for j in range(0, spaces): print(" ", end = "") for j in range(0, i + 1): print("* ", end = "") spaces = spaces - 1 print("") Рис. 7.3 Напишем функцию для этого вывода. In [10]: def pattern_RT(n): spaces = n - 1 for row in range(0, n): for space in range(0, spaces): print(” ", end = "") for star in range (0, row + 1): print!"* ", end="") spaces = spaces - 1 print!"") In [11]: pattern_RT(6) Результат вывода функции см. на рис. 7.3.
Проект 1: Рисунки из символов с помощью циклов и функций | 175 7.1.4. Прямоугольный треугольник вверх ногами Рассмотрим фигуру, представленную на рис. 7.4. Нам нужно вывести количество звездочек в обратном порядке по сравнению с но­ мерами строк, т. е. в первой строке должно быть 6 звездочек, в последней строке — одна. Поэтому первый цикл будем перебирать в обратном порядке с шагом -1. In [12]: row = 6 for i in range(row, 0, -1): # диапазон for j in range(0, i): print("* ", end="") print("") Рис. 7.4 В этом примере я намеренно не пишу код функций, чтобы вы могли попрактико­ ваться самостоятельно. Уверен, что вы справитесь. Помните, что определение функции — это просто оболочка вокруг вашего цикла. 7.1.5. Стрелка вправо Рассмотрим фигуру, представленную на рис. 7.5. In [13]: row = 11 peak = row //2+1 for i in range(0, peak): for j in range(0, i): print("* ", end="") print("") for i in range (peak, 0, -1): for j in range(0, i): print("* ”, end="") print("") Рис. 7.5
176 Гпава 7 | 7.1.6. Практические задания Рисунок 1: Рисунок 2: ****** ***** * * * * * * ★ * * * * * * * * * * ***** * ★ ★*★★★ ****** ***** * * * * * * * * * ★ Рисунок 3: * Рисунок 4: **************** * ★★★★★★* * ****** * * * * ***** ★ * * * * * * * * ★ Рисунок 5: ****** ***** * * * * * * * * * * * * * * ***** ****** ***** **** ★** ** * ★★★***★ ****** ***** **** *** ** *
Проект 1: Рисунки из символов с помощью циклов и функций | 177 7.2. Рисунки с помощью цифр Фигуры, которые мы делали из символа *, можно создавать с помощью любого другого символа. Разницы нет. Но когда дело доходит до последовательных чисел, с ними все немного сложнее. Мы воспользуемся тем же подходом, как и ранее. Начнем с более простых примеров, чтобы с их помощью лучше понять, как это реализовать. 7.2.1. Прямоугольный треугольник Рассмотрим фигуру на рис. 7.6. Этот шаблон похож на те, которые мы уже видели, с тем лишь отличием, что фигу­ ра состоит из цифр, и цифры меняются. In [14]: row = 6 for i in range(0, row + 1): for j in range(0, i): print(i, end=" ") # вывод чисел по строкам print("") 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 Рис. 7.6 Функция для такого вывода будет выглядеть так: In [15]: def numpatternl(n): for i in range(0, n + 1): for j in range(0, i): print(i, end=" ") print("") In [16]: numpatternl(6) Результат вывода данной функции см. на рис. 7.6. 7.2.2. Прямоугольный треугольник 2 Рассмотрим фигуру на рис. 7.7. Обратите внимание, что здесь числа увеличиваются не сверху вниз, а слева направо. In [17]: row = 6 for i in range(0, row + 1): for j in range(1, i + 1): print(j, end =" ") print("")
178 | Гпава 7 1 1 2 12 3 12 3 4 1 2 3 4 5 1 2 3 4 5 6 Рис. 7.7 Функция для числового вывода: In [18]: def numpattern2(n): for i in range(0, n + 1): for j in range(1, i + 1): print(j, end =" ") print!'"') In [19]: numpattern2(6) Результат вывода данной функции см. опять на рис. 7.7. 7.2.3. Прямоугольный треугольник вверх ногами Рассмотрим фигуру на рис. 7.8. In [20]: row = 6 num = 1 for i in range(row, 0, -1): for j in range(0, i): print(num, end=" ") num = num + 1 print ('"') 111111 2 2 2 2 2 3 3 3 3 4 4 4 5 5 6 Рис. 7.8 Функция будет такая: In [21]: def numpattern3(n): num = 1 for i in range(n, 0, -1): for j in range(0, i): print(num, end = " ") num = num + 1 print ('"') In [22]: numpattern3(6) Результат вывода данной функции см. на рис. 7.8.
Проект 1: Рисунки из символов с помощью циклов и функций 7.2.4. Треугольник из обратных чисел Построим фигуру, представленную на рис. 7.9. In [23]: row = 6 for i in range(0, row + 1): for j in range(i, 0, -1): print(j, end=" ") print 1 2 1 3 2 1 4 3 21 5 4 32 1 6 5 43 2 1 Рис. 7.9 Попробуйте написать функцию для этого вывода самостоятельно. 7.2.5. Треугольник из квадратов обратных чисел Код для фигуры на рис. 7.10: In [24]: row = 6 for i in range (0, row + 1): for j in range(i, 0, -1): print(j ** 2, end=" ") print("") 4 1 9 4 1 16 9 4 1 25 16 9 4 1 36 25 16 9 4 1 Рис. 7.10 7.2.6. Ромб Код для ромба на рис. 7.11: In [25]: row = 6 spaces = row - 1 b = 1 for i in range(1,row +1): for j in range(0, spaces): printC ", end="") for j in range(0, b): print(i, end=" ") | 179
180 | Гпава 7 spaces = spaces - 1 b = b + 1 print("") spaces = 1 b = row - 1 for i in range(row-l, 0, -1): for j in range(0, spaces): print(" ", end="") for j in range(0, b): print (i, end = " ") spaces = spaces + 1 b = b -1 print!"") 1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 5 5 5 5 5 4 4 4 4 3 3 3 2 2 1 Рис. 7.11 Давайте определим функцию для этого вывода. In [26]: def numpattern6(n): spaces = n - 1 num_count = 1 for row in range (1, n + 1): for i in range(0, spaces): print (" ", end= "") for num in range(0, num_count): print(row, end= " ") print("") spaces = spaces - 1 num_count = num_count + 1 spaces = 1 num_count = n - 1 for row in range(n - 1, 0, -1): for i in range(0, spaces): print!" ", end = "") for num in range(0, num_count): print(row, end= " ")
Проект 1: Рисунки из символов с помощью циклов и функций spaces = spaces + 1 num_count = num_count - 1 print ("") In [27]: numpattern6(6) Результат вывода данной функции см. на рис. 7.10. 7.2.7. Ромб с другим направлением чисел Теперь рассмотрим несколько иной ромб, представленный на рис. 7.12. In [28]: row = б spaces = row num_count = 1 for row in range(0, row +1): for i in range(0, spaces): print!" ", end= "") for num in range(1, num_count): print(num, end= " ") print("") spaces = spaces - 1 num_count = num_count + 1 spaces = 1 num_count = row for row in range(row, 0, -1): for i in range(0, spaces): print(" ", end = "") for num in range (1, num_count): print(num, end= " ") spaces = spaces + 1 num_count = num_count - 1 print("") 1 1 2 1 2 3 12 3 4 1 2 3 4 5 1 2 3 4 5 6 1 2 3 4 5 12 3 4 12 3 1 2 1 Рис. 7.12 | 181
182 | Гпава 7 Давайте посмотрим на функцию с этим выводом. In [29]: def numpattern7(n): spaces = n num_count = 1 for row in range(0, n + 1): for i in range(0, spaces): print(" ", end= "") for num in ranged, num_count): print(num, end= " ") print ('"') spaces = spaces - 1 num_count = num_count + 1 spaces = 1 num_count = n for row in range(n, 0, -1): for i in range(0, spaces): print (" ", end = "") for num in range(1, num_count): print(num, end= " ") spaces = spaces + 1 num_count = num_count - 1 print ("") In [30]: numpattern7(6) Результат вывода данной функции см. на рис. 7.12. 7.2.8. Стрелка влево Рассмотрим фигуру на рис. 7.13. In [31]: row = 6 spaces = row-1 num_count = 1 for i in range(0, row): for j in range(0, spaces): print!" ", end= "") for num in range(0, num_count): print(num, end= "") print ('"') spaces = spaces - 1 num_count = num_count + 1 spaces = 1 num_count = row -1 for i in range(row, 0, -1): for j in range (0, spaces): print(" ", end = "")
Проект 1: Рисунки из символов с помощью циклов и функций for num in range(0, num_count): print(num, end= "") spaces = spaces + 1 num_count = num_count - 1 print("") О 01 012 0123 01234 012345 01234 0123 012 01 О Рис. 7.13 Напишите функцию для этого вывода самостоятельно. 7.2.9. Практические задания Рисунок 1: Рисунок 2: Рисунок 3: 6 6 6 6 6 6 6 6 6 6 6 6 1 2 3 6 6 6 6 6 5 5 5 5 5 6 6 6 6 5 5 5 5 4 5 6 6 6 6 5 5 5 7 8 9 10 6 6 5 5 6 5 Рисунок 4: Рисунок 5: 1 654321123456 2 4 8 1 2 4 1 2 16 32 8 16 4 8 2 4 1 2 64 32 64 16 32 8 16 4 128 65432 23456 1 8 6543 3456 1 2 4 1 21 6 5 4 6 5 6 4 5 6 5 6 6 | 183
184 | Гпава 7 7.3. Резюме В этой главе мы на практике показали, как в Python работают циклы. Кроме того, мы на простых примерах попрактиковались в работе с циклами и функциями в Python. Вы увидели, что код, выполняющий определенные действия, можно легко преобразовать в функцию и использовать повторно. Вы получили навыки исполь­ зования многих концепций, таких как: ♦ создание простейших геометрических фигур с помощью символов; ♦ использование цикла for; ♦ инициализация и использование переменных в циклах и функциях; ♦ использование функции print (); ♦ создание собственных функций; ♦ преобразование кода в функцию.
8 Структуры данных и последовательности Название «структуры данных» говорит само за себя. Это структуры, в которых совместно хранятся определенные данные. В Python есть четыре встроенных структуры данных. ♦ списки; ♦ кортежи; ♦ множества; ♦ словари. В этой главе мы рассмотрим все эти структуры данных и узнаем о каждой из них подробнее. Эти типы лежат в основе понимания Python, поскольку встроенные структуры данных широко используются и их понимание невероятно важно для освоения Python. Прежде чем переходить к структурам данных, давайте изучим основные операции со строками, знать которые полезно для понимания структур данных. Некоторые из них мы уже рассмотрели в разд. 3.2. Посмотрим, что еще можно делать со стро­ ками. 8.1. Строки Строки являются объектами в Python, а именно экземплярами класса str. И пусть вас не смущают эти две фразы, потому что они означают одно и то же. Давайте разберемся. В Python все типы данных являются классами. Так, строки относятся к классу str, целые числа относятся к классу int, числа с плавающей запятой — к классу float и т. д. В Python класс — это определение объекта, а объект — это экземпляр класса. Мы узнаем больше о классах в следующих главах, и тогда этот момент станет вам более понятен. Строки можно задать несколькими способами. Их можно заключать в одинарные ('') или двойные кавычки ("") — результат будет одинаковый. Их также можно за­ ключать в три кавычки, одинарные или двойные. Использование трех кавычек дает возможность записывать строки более чем в одну строку. Примеры: 'строка' "строка" '''строка'1' """строка"""
186 Гпава 8 | Все эти строки одинаковы. Введите эти значения в Jupyter Notebook и запустите, чтобы увидеть результат. Проверьте типы полученных объектов и выведите их на экран. Вы заметите, что у всех этих строк одинаковое значение и тип. Попробуйте вариант с тройными кавычками. Нажмите клавишу <Enter> после первых трех ка­ вычек, чтобы вставить пустые строки между кавычками и строкой, а затем снова напечатайте значение. Обратите внимание на разницу. 8.1.1. Строковые операции Строки — это объекты, и, как у любых объектов, у них есть методы, которые мож­ но применять. Давайте рассмотрим методы capitalize о, upper о, lower о, swapcase о, format (), которые являются методами класса str. In [1]: х = "nilabh" print(x) |nilabh In [2]: x = "nilabh".capitalizeO print(x) |Nilabh In [3]: x = "nilabh".upper() print(x) [nilabh In [4]: x = "Nilabh".swapcase() print(x) |nILABH Примечание Строки — это неизменяемые объекты. А что тогда происходит, когда мы выполняем строковые операции? Вам наверняка интересно, как мы можем изменять неизменяе­ мый объект. А они действительно неизменяемы? Да, это действительно неизменяемые объекты. На самом деле происходит следую­ щее: каждая строковая операция создает новый объект, потому что неизменяемый объект изменить нельзя. Проверим на практике. In [5]: si = "Nilabh" s2 = "Nilabh" In [6]: # проверим, являются ли si и s2 одним и тем же объектом si is s2 |Out[6]: In [7]: True # убедимся, проверив идентификаторы print(id(sl)) print(id(s2))
Структуры данных и последовательности | 187 3083324156592 3083324156592 Видно, что это идентичные объекты, занимающие одно и то же место в памяти. Те­ перь применим к ним некоторые строковые операции и снова проверим идентифи­ каторы. In [8]: s3 = si.upper() print(s3 is si) print(id (s3)) print(id(si)) False 3083324020464 3083324156592 Как видите, si остался тем же объектом, a s3 — это новый объект. 8.1.2. Форматирование Теперь посмотрим, что делает метод format(). Мы вкратце уже познакомились с ним, когда говорили о функции print (). Но это, по сути, строковый метод, и его можно использовать независимо от print (). Для использования этого метода в строке должны быть заполнители, в которые по­ мещаются аргументы метода format о при выполнении. Это позиционный метод, если не указано иное. Это означает, что аргументы в результирующей строке появ­ ляются на тех же позициях, что и в format (). Рассмотрим примеры. In [9]: # 8, 9 и "ten" появятся в указанном порядке х = "seven, (}, {} and {}".format (8, 9, "ten") print(x) |seven, 8, 9 and ten Мы можем изменить очередность, указав позиции аргументов в заполнителях. Посмотрим, как это сделать. In [10]: # 8, 9 и "ten" располагаются в указанных позициях х = "seven, (2), {1} and (0}". format(8, 9, "ten") print(x) |seven, ten, 9 and 8 Метод format о также можно использовать для выравнивания строк и создания строки нужной длины. Если исходная строка короче, она будет дополнена пробе­ лами. Посмотрим, как это работает. In [11]: # 8, 9 и "ten" будут дополнены пробелами справа или слева, # в зависимости от знака '<’ или '>' после двоеточия х = "seven, print(x) |seven, ten , [2:<9], {1:>9} and {0:9}".format(8, 9, "ten") 9 and 8
188 | Гпава 8 Как вы заметили, строки прижимаются к левому или правому краю в направлении символов (<) или (>) соответственно. Так, строка "ten" выровнена по левому краю, а правая часть дополнена пробелами. При желании мы можем дополнять строки 1 о' вместо пробелов. In [12]: # 8, 9 и "ten" будут дополнены 'О' справа или слева, # в зависимости от знака '<' или '>' после двоеточия х = "seven, {2:<09}, {1:>09} and {0:>09}''.format(8, 9, "ten") print(x) |seven, tenOOOOOO, 000000009 and 000000008 Обратите внимание, что количество нулей разное и зависит от аргумента в запол­ нителе. Причина в том, что число после (-.) в заполнителе означает общую длину строки, и значение аргумента дополняется нулями до этой длины. Поскольку стро­ ка "ten" уже имеет длину 3, в строке появляется всего 6 нулей. Существует другой, новый способ форматирования строк, но он работает только в Python 3.6 и более поздних версиях. Этот метод называется f-строками. In [13]: # В f-строках можно использовать переменные в заполнителях а = "8" Ь = "9" с = "ten" х = f'seven, [a], {b} and {с}" print(х) |seven, 8, 9 and ten /-строки работают аналогично строковому методу format(). Попробуйте изменить примеры с методом format(), которые мы разбирали ранее, используя /-строки, и сравните результаты самостоятельно. 8.1.3. Методы split() и join() Разделить строку можно с помощью метода split (). Python находит в строке про­ белы и символы переноса и возвращает список всех слов из строки. In [14]: text = ('Put several strings within parentheses ' 'to have them joined together.') print(text.split ()) ['Put', 'several' 'together.'] 'strings', 'within' 'parentheses', 'to', 'have', 'them', 'joined', По умолчанию метод split о делит строку по пробелам. Но мы можем изменить это поведение. Давайте разделим ту же строку, но по буквам "i" вместо пробелов. In [15]: print(text.split("i")) ['Put several str', 'ned together.'] 'ngs w', 'th', 'n parentheses to have them jo',
Структуры данных и последовательности С методом In [16]: split () | 189 разобрались. Теперь посмотрим, как строки можно объединить. split_text = text.split)) print(split_text) ['Put', 'several' 'together.'] In [17]: 'strings', 'within', 'parentheses', 'to', 'have', 'them' 'joined', join_text = " ".join(split_text) print(join_text) [Put several strings within parentheses to have them joined together. В примере видно, что перед методом join)) мы использовали пробел " ", а в качест­ ве аргумента— список слов, которые нужно объединить. Мы можем объединять слова с помощью любой строки. Например, давайте соединим слова символом In [18]: join_textl = join(split_text) print(join_textl) Put-several-strings-within-parentheses-to-have-them-joined-together . Методы split)) и join)) — относительно сложные операции. Но объектная модель Python делает всю сложную работу за нас. 8.2. Списки Чтобы понять, что представляют собой списки в Python, возьмите в качестве при­ мера любой список, который попадался вам на глаза в повседневной жизни. Это может быть список дел, список покупок, или даже список фильмов и сериалов для просмотра, или список игр, в которые хочется поиграть. У списков в Python есть важные 3 свойства: ♦ упорядоченность; ♦ последовательность; ♦ итерируемость. Какие списки мы можем использовать? ♦ названия предметов, фильмов или игр (в основном это текстовые строки); ♦ числовые данные; ♦ символы; ♦ что угодно. По сути, список Python ничем не отличается от привычного вам списка. Осталось сделать лишь две вещи: ♦ разделить элементы запятыми (тогда как в обычном списке элементы находятся на разных строках); ♦ заключить элементы списка в квадратные скобки ([]), чтобы Python понимал, что это список.
190 | Гпава 8 Ниже приведены два примера списков, один из которых представляет собой обыч­ ный повседневный список (рис. 8.1), а другой — этот же список, но на Python. Список фильмов и сериалов, которые я хочу посмотреть: • Побег из Шоушенка • Крестный отец • Аватар • Терминатор-2: Судный день • 24 часа • 12 разгневанных мужчин • Три амигос! • Игра престолов Рис. 8.1. Список фильмов и сериалов In [19]: ListOfMovies = ['Побег из Шоушенка', 'Аватар', '24 часа', 'Крестный отец', 'Терминатор-2: Судный день', '12 разгневанных мужчин', 'Три амигос!', 'Игра престолов'] После создания списку выделяется место в памяти, а при вызове список возвра­ щается In [20]: ListOfMovies Out [20]: ['Побег из Шоушенка', 'Крестный отец', 'Аватар', 'Терминатор-2: Судный день', '24 часа', '12 разгневанных мужчин', 'Три амигос!', 'Игра престолов'] После создания списка вы можете вносить в него изменения с помощью различных функций и операций над списками. Вы можете добавлять, удалять и искать элемен­ ты в списке. Список является изменяемым типом данных. Списки могут содержать: ♦ числа; ♦ строки; ♦ выражения; ♦ все вышеперечисленное.
Структуры данных и последовательности | 191 Кроме того, список может содержать в себе другие списки. Итак, список— это просто контейнер. У этого контейнера есть некоторые свойства, которые делают его простым и полезным в использовании. 8.2.1. Индексы и срезы Как и строки (и другие встроенные типы последовательностей), списки можно ин­ дексировать и делать срезы. Мы создадим простой список чисел, чтобы на его примере рассмотреть индекса­ цию и срезы’. In [21]: even = [2, 4, 6, 8, 10, 12, 14] In [22]: even[0] Out[22]: 2 In [23]: even[-l] |Out[23]: # объект списка по индексу 14 In [24]: even[1:4] |Out[24]; [4, б, 8] # срез возвращает новый список Списки также поддерживают операцию слияния (+). In [25]: |Out[25]: even+[16, 18, 20, 22] [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22] В отличие от неизменяемых строк, списки являются изменяемым типом данных, т. е. их содержимое можно изменять. In [26]: squares = [1, 4, 9, 17, 25] # квадраты чисел, с ошибкой # 4 в квадрате равно 16, а не 17! |0ut[26]: In [27]: squares [1, 4, 9, 17, 25] squares[3] =16 ~~ # замена неправильного значения squares |Out[27]: [1, 4, 9, 16, 25] Встроенная функция lend также применима к спискам. In [28]: I Out[28]: len(squares) 5 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
192 | Глава 8 8.2.2. Методы списков1 Методы списков перечислены в табл. 8.1. ТАБЛИЦА 8.1 Метод Описание list.append(x) Добавление элемента x в конец списка. Эквивалентно alien (a):] = [х] list.extend(iterable) Добавление в список всех элементов из iterable. Эквивалентно a[len(a):] = iterable list.insert(i, x) Вставка элемента х на заданную позицию. Первый аргумент — это индекс элемента, перед которым нужно выполнить вставку, поэтому a.insertfO, х) вставляет элемент в начало списка, a a.insert(1еп(а), х) эквивалентно a.append(х) list.remove(x) Удаление из списка первого элемента, значение которого равно х. Если такого элемента нет, возникает ошибка valueError list.popl[i]) Удаляет элемент в данной позиции в списке и возвращает его. Если индекс не указан, a.pop о удаляет и возвращает последний элемент в списке. (Квадратные скобки вокруг i в сигнатуре метода означают, что этот параметр является необязательным и не нужно печатать эти скобки при вызове метода. Это обозначение часто встречается в справочниках по библиотекам Python.) list.clear!) Удаляет все элементы из списка. Эквивалентно del а[: list.index(x[, start!, end]]) Возвращает индекс первого элемента, значение которого равно х. Воз­ вращает ошибку valueError, если такого элемента нет. Необязательные аргументы start и end интерпретируются как срез и используются для ограничения области поиска в списке. Возвращается индекс относительно начала списка, а не от аргумента start list.count(x) Сколько раз значение хвстречается в списке list.sort![key=None, reverse=False]) Сортирует элементы списка (необязательные аргументы можно использовать для настройки сортировки) list.reverse() Меняет порядок элементов списка на обратный list.copy() Возвращает копию списка. Эквивалентно [: ] В следующем примере эти методы применяются к списку fruits. Чтобы все по­ смотреть в одном окне, выполните код в консоли IPython, а не в Jupyter Notebook. Чтобы понять тему лучше, поэкспериментируйте со своими списками. >» fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana'] »> fruits. count (' apple') 2 »> fruits. count (' tangerine') 0 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Структуры данных и последовательности | 193 >» fruits. index (' banana') 3 # ищет значение в списке, начиная с позиции 4 »> fruits, index ('banana', 4) 6 »> fruits. reverse () »> fruits ['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange'] 'banana', ’pear*, 'apple', 'orange', »> fruits, append ('grape') »> fruits ['banana', 'apple', 'kiwi', 'grape'] »> fruits.sort() »> fruits ['apple', 'apple', 'banana' , 'banana' ’grape’ , 'kiwi', 'orange', 'pear'] »> fruits.pop() ’pear’ 8.2.3. Списковые включения Списковые включения — это краткий и элегантный способ создания списков. Базо­ вая структура спискового включения выглядит следующим образом: результат = [выражение for элемент in список if условие] Это выражение эквивалентно циклу for, но, как я уже сказал, списочные выражения выглядят элегантнее. Равнозначный цикл для создания такого же списка будет выглядеть так: for элемент in список: if условие: выражение Давайте рассмотрим несколько примеров списковых включений. In [29]: # создание простого списка из букв [i for i in 'asia'] |out[29]: In [30]: ['a', 's', 'i', 'a'] # создание списка из чисел диапазона mylist = [i for i in range(10)] mylist |Out[30]; [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] В приведенных примерах мы не указывали никаких условий. In [31]: # создание списка из четных чисел от 0 до 20 evens = [i for i in range(20) if i % 2 == 0] |Out[31]: evens [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] ~
194 | In [32]: Гпава 8 # создание списка типа [х, хх, ххх, у, уу, ууу, z, zz, zzz] mylist = ['x', 'у', 'z'] [i * n for i in mylist for n in range (1,5)] Out[32]: 'zzzz'] ['x', 'хх', 'ххх', 'xxxx', 'у', 'уу', 'yyy', 'УУУУ', 'z', 'zz', 'zzz', В следующем примере давайте сравним списковое включение с циклом for, кото­ рый возвращает такой же результат. Вы удивитесь сходству между ними, а также оцените простоту и элегантность кода со списковыми включениями. Мы хотим создать вот такой список: [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]. In [33]: # создание списка с помощью цикла for combs = [] for х in [1, 2, 3]: for у in [3, 1, 4]: if x != y: combs.append((x, y)) combs |Out[33]: In [34]: [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] # создание списка с помощью спискового включения [ (х, у) for х in [1, 2, 3] for у in [3, 1, 4] if x != у] |Out[34]: [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)] Обратите внимание на то, что порядок операторов for и if в обоих фрагментах оди­ наковый. Списковые включения можно использовать для создания списка элементов, списка кортежей, словарей, множеств. 8.2.4. Оператор del Если нужно удалить элемент из списка, указав его индекс, а не значение, вы можете использовать оператор del. Он отличается от метода pop (), который еще и возвращает значение элемента. Оператор del также можно использовать для удаления фрагмента списка или очи­ стки всего списка. Например: In [35] : х = [-2, -4, 5, 8, 2.2, 44] del х[0] х |Out[35]: In [36]: [-4, 5, 8, 2.2, 44] del x[2:4] X |Out[36]: [-4, 5, 44]
Структуры данных и последовательности Оператор del | 195 можно использовать для удаления целых переменных: In [37]: del х In [38]: х Traceback (most recent call last) NameError <ipython-input-53-6fcf9dfbd479> in <module> --- > 1 x NameError: name 'x' is not defined Ссылка на имя x в последней строке является ошибкой (по крайней мере до тех пор, пока ему не будет присвоено новое значение). 8.3. Кортежи' Кортеж состоит из ряда значений, разделенных запятыми, например: In [39]: In [40]: |Out[40]: -t = 1234, 5678, t 'xyz' # здесь переменная t - это кортеж # обратите внимание, что кортеж при выводе заключен в скобки (1234, 5678, In [41]: u = t, In [42]: u Out[42]: ((1234, 5678, ('a', 'xyz') 'b', 'c') 'xyz'), # кортеж u, состоящий из вложенных кортежей ('а', 'b', 'с')) Как вы видите, при выводе на экран кортежи всегда заключаются в круглые скобки, поэтому вложенные кортежи интерпретируются правильно. Они могут вводиться как с круглыми скобками, так и без них, хотя часто скобки все равно необходимы (если кортеж является частью более крупного выражения). Нельзя менять отдель­ ные элементы кортежа, но можно создавать кортежи, которые содержат внутри себя изменяемые объекты, такие как списки. Кортежи похожи на списки, но с двумя отличиями. ♦ Кортежи неизменяемы, а списки изменяемы. ♦ Кортежи заключаются в круглые скобки, а списки — в квадратные. Возникает вопрос: зачем в Python есть две столь похожие встроенные структуры данных — кортежи и списки? Пожалуй, лучше всего сказать, что «так исторически сложилось». Сейчас нас будет больше интересовать, в чем разница в их использо­ вании в Python. ♦ Хотя кортежи и похожи на списки, они часто используются в разных ситуациях и для разных целей. ♦ Кортежи неизменяемы и обычно содержат неоднородную последовательность элементов, доступ к которым осуществляется посредством распаковки или ин­ дексации (или по имени атрибута в случае именованных кортежей). 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
196 | Глава 8 ♦ Списки изменяемы, их элементы обычно однородны, а доступ к ним осуществ­ ляется путем перебора списка. Как мы видели ранее, кортежи можно создавать без круглых скобок, но это не очень хорошая практика. В этой книге при создании кортежей мы всегда будем ис­ пользовать круглые скобки. Где и почему лучше использовать кортежи вместо списков? ♦ Когда важна скорость выполнения программы, предпочтительнее использовать кортежи. Программа с кортежами выполняется быстрее по сравнению с такой же программой, но на списках. Но при использовании небольших кортежей и списков разница не ощущается. ♦ Когда важна целостность данных и вы не хотите, чтобы ваши данные изменя­ лись во время выполнения программы. Использование кортежа вместо списка защищает данные от случайного изменения во время выполнения (помните, что кортежи неизменяемы). ♦ В Python есть еще один тип данных, называемый словарем. Ключи словаря должны быть неизменяемыми, поэтому для них можно использовать кортежи, а вот списки — нельзя. 8 .3.1. Методы кортежей Почти все методы списков также применимы и к кортежам. Вы уже знаете, что кортежи неизменяемы. Следовательно, методы и функции, которые изменяют спи­ ски, для кортежей использоваться не могут. Здесь мы специально не будем рассматривать методы кортежей. Самостоятельно попробуйте все методы списков на кортежах и посмотрите, чем кортежи похожи на списки, а чем отличаются от них. 8.4. Множества В Python есть специальный тип данных для хранения множеств. Множество — это неупорядоченная коллекция неповторяющихся элементов. Они используются в основном для проверки вхождения элементов во множество и для устранения дубликатов. Множества также поддерживают математические операции, такие как объединение, пересечение, разность и симметричная разность. Множество — это неупорядоченный тип данных, который является итерируемым, изменяемым и не имеет повторяющихся элементов. Класс множества в Python со­ ответствует математическим множествам1. Поскольку множества не упорядочены, к их элементам нельзя получить доступ через индекс. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Структуры данных и последовательности | 197 Для создания множеств можно использовать фигурные скобки {) или функцию set (). In [43]: colours = {'red', 'black', 'blue', 'orange', 'red', 'pink', # при создании множества есть несколько дубликатов, # но далее остаются лишь уникальные элементы 'white', 'black'} colours |put[43]: In [44]: {'black', 'blue', 'orange', 'pink', 'red', 'white'} # быстрая проверка на вхождение в множество 'red' in colours |Out[44]: In [45]: |Out[45]: True 'purple' in colours False Примечание Для создания пустого множества нужно использовать функцию set о, а не {}, т. к. пус­ тые фигурные скобки создают пустой словарь — структуру данных, которую мы обсу­ дим в следующем разд. 8.5. 8.4.1. Операции над множествами Множества поддерживают те же операции, что и в работе с математическими мно­ жествами. In [46]: # уникальные буквы в словах а = set('abracadabra') b = set('alacazam') In [47]: | Out [47]: In [48]: |out[48]: In [49]: a {'a', # уникальные буквы в множестве а 'b', 'd', 'г'} # уникальные буквы в множестве b b {'а', 'с', 'с', '!', 'm', 'z'} # для сравнения, если использовать список triallist = list('abracadabra') triallist # все буквы сохраняются в порядке их появления в списке | Out [49]: ['a', In [50]: a - b Out[50]: {'b', In [51]: a|b |Out[51]: {'a', 'b', ’r’, 'a’, ’c*, ' а ’, 'd', 'а', 'b', 'г', 'а'] # буквы, которые есть в множестве а, но не в b 'd', 'г'} # буквы, которые есть в а, или Ь, или в обоих множествах 'b', 'с', 'd', '1', ’ш’, 'Г', 'Z'}
198 | Глава 8 In [52]: а & b |Out[52]: ('а', In [53]: |put[53]: а л b # буквы, которые есть в а или Ь, но не в обоих сразу ('b', 'd', 'm', 'г', 'z'} # буквы, которые есть в множествах а и b одновременно 'с'} 1 Операции, аналогичные списковым включениям, применимы и для множеств: In [54]: | Out[54]: а = {х for х in 'abracadabra' if х not in 'abc'} a {'d', 'r'} 8.4.2. Методы множеств Практически все методы списков также применимы и к множествам. Множества не упорядочены, поэтому методы, использующие индексацию, здесь не используются. Попробуйте все методы списков на множествах и сами проверьте, как перебирать и изменять множества. В табл. 8.2 приведены методы для работы с множествами, и среди них вы можете заметить дополнительные методы, выполняющие математические операции над множествами1. ТАБЛИЦА 8.2 Метод Описание add О Добавляет элемент в множество сору() Возвращает копию множества clear() Удаляет все элементы из множества discard() Удаляет указанный элемент из множества pop () Удаляет произвольный элемент из множества remove() Удаляет указанный элемент. Если такого элемента нет в множестве, вернется ошибка symmetric_difference () Возвращает симметричную разность двух множеств symmetric_difference_update() Вставляет симметричную разность этого множества и другого union() Возвращает объединение множеств difference() Возвращает разницу между двумя или более множествами difference_update() Удаляет элементы из этого множества, которые также включены в другое множество update() Объединяет множество с другим intersection() Возвращает пересечение двух других множеств 1 W3Schools, 2020 (https://www.w3schools.com/python/python_sets.asp) [48].
Структуры данных и последовательности | 199 ТАБЛИЦА 8.2 (окончание) Метод Описание intersection_update() Удаляет из множества элементы, которых нет в другом множестве isdisjointl) Проверяет, есть ли у двух множеств пересечение issubset() Проверяет, является ли это множество подмножеством другого issuperset () Проверяет, является ли другое множество подмножеством первого 8.5. Словари Словарь— это еще один встроенный тип данных Python. Это неупорядоченный набор единиц данных. В обычных словарях, как правило, есть ключ, т. е. слово или элемент, значение ко­ торого объясняется в словаре. Это объяснение и есть значение ключа. В Python то же самое. Лучше всего рассматривать словарь как пары ключ : значение с требованием о том, чтобы ключи в пределах одного словаря были уникальными. Пустой словарь созда­ ется с помощью пары фигурных скобок {}. Затем через запятую перечисляются пары ключ-, значение. Словарь также можно создать с помощью встроенной функции diet о1. Ключ в словаре — это уникальный и неизменяемый тип данных, такой как строка, число или кортеж. Другими словами, в качестве ключей можно использовать толь­ ко простые типы данных. In [55]: # небольшой пример словаря из телефонных номеров друзей household = {'ramesh': 9893200000, 'surabhi': 9893200311} household |Out[55]: In [56]: {'ramesh': 9893200000, ’surabhi1: 9893200311} # добавить нового друга household!'sush'] = 9893200422 |Out[56]: In [57]: household {'ramesh': 9893200000, 'surabhi': 9893200311, 'sush': 9893200422} # словарь индексируется по ключам, а не по порядку, # как список или строка household['surabhi'] |Out[57]: 9893200311 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
200 | Гпава 8 Конструктор diet о строит словарь непосредственно из последовательности пар (ключ, значение): In [58]: |Out[58]: diet([('заре', 4139), (’guide', 4127), ('jack', 4098)]) {'sape': 4139, 'guido': 4127, 'jack': 4098} Для создания словарей из произвольных выражений для ключей и значений можно использовать синтаксис, аналогичный списковым включениям. In [59]: # Квадраты чисел {х : х**2 for х in (2, 3, 4 ,5)} |Out[59] : {2: 4, 3: 9, 4: 16, 5: 25} Когда ключи являются простыми строками, иногда проще указывать пары с по­ мощью именованных аргументов. In [60]: |Out[6Q]: diet(sape=4139, guido=4127, jack=4098) {'sape': 4139, 'guido': 4127, 'jack': 4098} 8.5.1. Методы словарей1 Метод Описание copy!) Возвращает колик} словаря clear!) Удаляет все элементы из словаря pop!) Возвращает значение ключа и удаляет эту пару из словаря popitem!) Удаляет произвольную пару из словаря и возвращает ее как кортеж get!) Обычный метод доступа к значению ключа values() Возвращает список всех значений словаря str!) Создает строковое представление словаря update() Добавляет в словарь или обновляет пары из другого словаря setdefault () Возвращает значение ключа, если он есть в словаре, или добавляет его в словарь со значением по умолчанию keys() Возвращает список всех ключей словаря items() Возвращает список, содержащий кортеж для каждой пары «ключ — значение» has_key() Возвращает true, если ключ присутствует в словаре, иначе false fromkeys() Создает новый словарь с ключами из указанной последовательности и заданными значениями по умолчанию type!) Возвращает тип переданной переменной emp () Сравнивает элементы двух словарей 1 GeeksforGeeks, 2020 (https://www.geeksforgeeks.org/python-dictionary/) [6].
Структуры данных и последовательности | 201 8.6. Перебор последовательностей в цикле1 При циклическом просмотре словаря ключ и соответствующее значение можно получить одновременно с помощью метода items (). In [61]: knights = {'Gallahad': 'the pure', 'Robin': 'the brave'} for k, v in knights.items(): print(k, v) Gallahad the pure Robin the brave При переборе последовательности индекс позиции и соответствующее значение можно получить одновременно С ПОМОЩЬЮ функции enumerate (). In [62]: for i, v in enumerate (['tic', 'tac', 'toe']): print(i, v) 0 tic 1 tac 2 toe При совместном переборе двух или более последовательностей можно объединять записи с помощью функции zip(). In [63]: questions = ['name', 'quest', answers = ['Lancelot', 'favorite color'] 'the Holy Grail', 'blue'] for q, a in zip(questions, answers): printl'What is your {0}? What is your name? What is your quest? It is {1}.'.format(q, a)) It is Lancelot. It is the Holy Grail. What is your favorite color? It is blue. Чтобы перебрать последовательность в обратном порядке, сначала укажите после­ довательность в прямом порядке, а затем вызовите функцию reversed (). In [64]: for i in reversed(range(1, 10, 2)): print (i) 7 5 3 1 Чтобы перебрать последовательность в отсортированном порядке, используйте функцию sorted (), которая возвращает новый отсортированный список, оставляя исходный список неизменным. In [65]: basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] for f in sorted(set(basket)): print (f) 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
202 | Гпава 8 apple banana orange pear Иногда очень хочется изменить список во время перебора, но при этом проще и безопаснее создать новый список. In [66]: import math raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float ('NaN'), 47.8] filtered_data = [ ] for value in raw_data: if not math.isnan(value) : filtered_data.append(value) In [67]: [Out[67]: filtered_data [56.2, 51.7, 55.3, 52.5, 47,8] 8.7. Резюме Эта глава была полностью посвящена встроенным структурам данных и последова­ тельностям Python. Мы изучили строки и их методы, форматирование и операции. Мы рассмотрели, как можно изменять строки, хотя они и неизменяемы. Затем были списки. Это один из самых популярных типов данных, в котором мож­ но хранить что угодно. Списки изменяемы, и ими можно элегантно управлять с по­ мощью списковых включений. Далее мы рассмотрели кортежи, которые очень похожи на списки, но они неизме­ няемы, поэтому используются по-другому. После этого были множества, которые сильно отличаются от списков и кортежей. Они не упорядочены, и, следовательно, от них нельзя брать индекс или срез, как от списков. Они содержат только уникальные значения и используются там, где нуж­ на определенная функциональность. Затем мы ввели словари, данные в которых хранятся в виде пар «ключ — значе­ ние». Они очень полезны во многих случаях. Последовательности можно перебирать в цикле. Некоторые из этих способов мы рассмотрели в последнем разделе. 8.8. Упражнения 8.8.1. Ответьте на вопросы 1. В чем разница между числами и строками в Python? Они взаимозаменяемы? 2. Как работает новый метод форматирования строк, представленный в версии Python 3.6? 3. Какие типы данных и последовательности могут храниться в списке?
Структуры данных и последовательности | 203 4. Какой результат даст приведенный оператор? Обоснуйте ответ. print('let\'s get back to work') 5. Списки можно изменять, но кортежи неизменяемы. Как вы понимаете это ут­ верждение? Как это влияет на использование обоих этих типов данных? 6. Какому оператору эквивалентны списковые включения? Чем они полезнее? 7. Кортежи представляют собой упорядоченную коллекцию, а множества— не­ упорядоченную коллекцию. Как вы понимаете это утверждение? Как это влияет на использование обоих этих типов? 8. Если требуется хранить уникальные элементы любого текста или коллекции, ка­ кой тип лучше использовать? Приведите пример, когда это может быть полезно. 9. Являются ли словари итерируемыми? Продумайте ответ. 8.8.2. Правда или ложь 1. Одну и ту же строку можно изменять с помощью строковых методов и сохра­ нять ее в той же области памяти. 2. Операция умножения строки на число возвращает строку с повторяющимися значениями. 3. Строки различаются в зависимости от используемых кавычек. 4. Индексирование работает со строками и списками, но не со множествами. 5. В списках может храниться только один тип данных. 6. Вставлять новое значение в кортеж нельзя. 7. Списковые включения — это элегантный метод управления списками. 8. Кортеж может содержать разные типы данных. 9. Кортежи заключаются в круглые скобки о, а списки заключаются в квадратные скобки []. 10. В словаре количество ключей и значений не обязательно должно быть одина­ ковым. 8.8.3. Практические задания 1. Используйте списковые включения для создания следующих списков: а) ['С, 'О', 'U', 'N', б) ['С, 'А', 'Т', 'СС, В) [[2], Г) [3], [[2, 3, 4, 5], Д) [(1,1), е) [4], (2,1), [3], 'Т', 'R', 'Y'] 'АА', 'ТТ', 'ССС, [4], [5], [4], [5], 'AAA', ' ТТТ' ] [6]] [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]] (3,1), (2,2), (1,3), (1,2), [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] (3,2), (2,3), (3,3)]
204 | Гпава 8 2. Создайте пустой список. Допустим, он называется 50 числами от 1 до 25 (числа могут повторяться). my list. Заполните его 3. В списке my list, созданном в предыдущем пункте, выполните поиск и узнайте, есть ли в нем числа 11, 18 и 20. Напишите код для поиска этих чисел. Кроме того, подсчитайте, сколько раз встречаются эти числа в списке. 4. Напишите код для вывода информации о том, сколько четных и нечетных чисел в списке my list. 5. Напишите код для создания из my list другого списка, в котором числа равны квадрату чисел в my list, но в обратном порядке. 6. Напишите функцию sorted_list(), которая принимает в качестве параметра спи­ сок и возвращает True, если список отсортирован в порядке возрастания, и False в противном случае. В качестве дополнительного условия вы можете считать, что элементы списка можно сравнивать с помощью операторов отношения <, > ит. д. 7. Напишите программу Python для ввода имен и номеров телефонов 10 ваших друзей, сохранения их в словаре и вывода номера телефона по заданному имени. 8. Напишите функцию remove duplicates (), которая принимает в качестве параметра список и возвращает новый список, содержащий только уникальные элементы из первого списка. Подсказка: они не обязательно должны сохранять порядок. 9. Напишите функцию для вычисления произведения элементов списка. Что про­ изойдет, если в функцию передать список строк? 8.8.4. Изучите самостоятельно 1. Попробуйте все методы списков использовать на кортежах и убедитесь в том, насколько они похожи и в то же время различаются. 2. В приведенном выше задании 1 из разд. 8.8.3 напишите циклы вместо всех спи­ сковых включений.
9 Ввод-вывод данных и работа с файлами 9.1. Ввод данных Ввод данных в Python можно осуществлять двумя способами. Первым способом мы уже пользуемся в процессе обучения. Мы набираем текст с кодом и числами для расчетов, пишем функции. Именно такой простой способ ввода данных в Python. Для этого мы используем какую-нибудь IDE. Например, я использую Jupyter Notebook и ввожу входные данные в ячейки кода, которые при выполнении либо генерируют выходные данные, либо нет (но при этом могут сохранять что-то в па­ мяти). Способы вывода данных мы рассмотрим чуть далее в этой главе. Когда мы пишем код с входными данными и запускаем его, мы выполняем стати­ ческие операции. Наши переменные уже определены и жестко запрограммированы в исходном коде. Есть другой способ ввода данных. Чтобы добиться гибкости выполнения, мы мо­ жем получать информацию от пользователя. В Python есть встроенная функция input (), которая делает именно это. Синтаксис функции input (): input (prompt} где prompt — это строка, которую мы хотим отобразить на экране. Этот параметр не обязательный и лишь помогает пользователю понять, что ему нужно ввести. Когда мы запускаем этот код: greetings = input("Say your greetings: ") то он предлагает пользователю ввести что-либо (рис. 9.1). In [*]: greetings « input("Say your greetings: ”) Say your greetings: || | Рис. 9.1. Работа функции input О в Jupyter Notebook Когда пользователь вводит свое приветствие в поле, оно выводится, как показано ниже: In [1]: greetings = input("Say your greetings: ") Say your greetings: Good Morning
206 Гпава 9 | Мы также можем попросить пользователя ввести входные данные для математиче­ ских вычислений. В следующем примере видно, что ввод не обязательно является строкой и может использоваться как угодно. In [2]: num = int(input("Enter the Number: ")) def even_odd(num): if num % 2 = 0: print("This is an even Number") # четное число else: print("This is an odd Number") even_odd(num) # нечетное # вызов функции Enter the Number: 9 This is an odd Number Мы сначала определили переменную num и присвоили ей значение, которое является динамическим целым числом (т. к. вводится пользователем). Затем мы определили функцию even odd (), которая принимает num в качестве аргу­ мента. Эта функция проверяет, является ли введенное пользователем число четным или нечетным. Повторите этот код в своей среде IDE или в Jupyter Notebook и по­ смотрите, что произойдет. Примечание Функция input о всегда возвращает строку. Если вам нужно число, необходимо преоб­ разовать эту строку в соответствующий тип данных с помощью встроенных функций into, float!) или complex!). В нашем примере используется функция into для преоб­ разования введенной пользователем строки в целое число. In [3]: # напишем интерактивный код, чтобы показать, как работает input() print("Hi, How are you doing?") name = input("What is your name: ") age = input("What is your age: ") print("() is not double your age".format(age * 2)) print("Hi {}, are you enjoying this Book?".format(name)) answer = input() if answer == "yes" or "Yes" or "YES": print("Thank you! Hope you learn with fun.") else: print("I hope it gets better going further.") Hi, How are you doing? What is your name: Nilabh
Ввод-вывод данных и работа с файлами | 207 What is your age: 34 3434 is not double your age Hi Nilabh, are you enjoying this Book? Yes Thank you! Hope you learn with fun. Запустите этот код в своей IDE. Вы заметите, что: 1. Функция input!) принимает все, что вы напечатаете. 2. Она возвращает строку. Что бы вы ни ввели, это будет строкой. Даже если у вас спросят, сколько вам лет, и вы введете число, функция input () вернет строку. 3. Пока вы не введете что-нибудь в ответ на запрос input (), процесс не будет вы­ полняться дальше. 4. Чем скорее вам понравится эта книга, тем лучше пойдет процесс обучения. 9.2. Форматированный вывод данных' В Python есть несколько способов вывести результат работы программы. Данные можно вывести на экран в удобочитаемой форме или записать в файл. В этой главе мы посмотрим, какие у нас есть возможности. До сих пор мы встречались только с двумя способами вывода значений: использо­ вание непосредственно выражения и функция print (). Часто вам нужно будет больше контроля над оформлением вывода, и просто вы­ вести значения через пробел будет недостаточно. Форматировать вывод можно несколькими способами. 9.2.1. Форматированные строки Форматированные строки (так называемые f-строки) позволяют включать значения выражений Python внутрь строки. Для этого перед самой строкой надо добавить префикс f или F, а выражение заключить в фигурные скобки {выражение}. In [4]: Name = "Nilabh" Year = 1998 f'{Name} was born in {Year)' |out[4]: 'Nilabh was born in 1998' В следующем примере выводится значение числа л внутри строки, заданной поль­ зователем. In [5]: import math print(f1The value of pi is approximately {math.pi)') |The value of pi is approximately 3.141592653589793 ' Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
208 | Гпава 9 После выражения может следовать необязательный спецификатор формата. Он по­ зволяет управлять форматированием. В следующем примере число п округляется до трех знаков после запятой. In [6]: import math print(f'The value of pi is approximately {math.pi:.3f}') |The value of pi is approximately 3.142 Если использовать целое число после двоеточия, то для вывода значения будет за­ дано минимальное количество символов по ширине. Это удобно для выравнивания столбцов. В приведенном ниже примере мы увидим, как это влияет на вывод. In [7]: # без спецификатора формата table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678} for name, phone in table.items(): print(f'{name} ==> {phone}') Sjoerd ==> 4127 Jack ==> 4098 Dcab ==> 7678 In [8]: # целое число после двоеточия задает минимальную ширину вывода table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678} for name, phone in table.items(): print(f'{name:10} ==> {phone:10}') Sjoerd ==> Jack ==> 4098 Dcab ==> 7678 4127 Для преобразования значения перед выводом можно использовать и другие моди­ фикаторы. Так, например, !а применит к значению функцию ascii о, is — функцию str (), а ! г — герг {). In [9]: animals = 'eels' print(f'Му hovercraft is full of {animals}.') # применим !r print(f'My hovercraft is full of {animals!r}.') My hovercraft is full of eels. My hovercraft is full of 'eels'. Вы можете найти дополнительную информацию в справочном руководстве по спе­ цификации формата Mini Language: https://docs.python.Org/3.7/library/string.html#formatspec 9.2.2. Строковый метод formatf) Основной способ использования метода In [10]: format () выглядит так: printf'We are the {} who say "{}!"'.format('knights', We are the knights who say "Ni!" 'Ni'))
Ввод-вывод данных и работа с файлами | 209 Фигурные скобки (заполнители) заменяются объектами, переданными в качестве аргументов метода format(). Число в фигурных скобках обозначает позицию аргу­ мента, переданного в format (). print('{0] and {1}'.format('spam', 'eggs')) print('{1} and {0}'.format('spam', 'eggs')) spam and eggs eggs and spam In [11]: Если в методе format о используются именованные аргументы, к их значениям обращаются по имени аргумента. print('This [food] is {adjective}.'.format(food='spam' , adjective='absolutely horrible')) | This spam is absolutely horrible. In [12]: Позиционные аргументы и именованные аргументы можно комбинировать произ­ вольным образом. In [13]: printf'The story of [0), {1}, and {other}.'.format('Bill', 'Manfred', other='Georg')) [The story of Bill, Manfred, and Georg. Если вам нужно вывести длинную строку, которую вы не хотите разбивать, удоб­ нее было бы ссылаться на переменные по имени, а не по позиции. Это можно сделать, просто передав словарь и используя квадратные скобки [] для доступа к ключам. In [14]: table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} printCJack: {0[Jack]:d}; Sjoerd: {0[Sjoerd] :d}; Dcab: {0[Dcab]:d}' .format(table)) |Jack: 4098; Sjoerd: 4127; Dcab: 8637678 Вы, наверное, заметили здесь спецификатор формата d после двоеточия. Он ис­ пользуется для перевода данных в нужный формат перед выводом. Обратите вни­ мание на небольшие изменения в коде и посмотрите, как изменился результат. In [15]: table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:c}; Dcab: {0[Dcab]:b}' .format(table)) |Jack: 4098; Sjoerd: §; Dcab: 100000111100110011101110 Что здесь произошло с выводом? Я не буду вам объяснять. Попробуйте самостоя­ тельно найти ответ, а также узнать много других вариантов форматирования на сайте: https://docs.python.Org/3.7/Iibrary/string.html#formatspec
210 | Глава 9 Продолжим работу с нашим примером. Того же результата можно было бы добиться, передав словарь в качестве имено­ ванного аргумента с помощью синтаксиса **. In [16]: table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}' .format(**table)) |Jack: 4098; Sjoerd: 4127; Dcab: 8637678 Это особенно удобно в сочетании со встроенной функцией vars (), которая возвра­ щает словарь, содержащий все локальные переменные. В следующем примере выводятся выровненные столбцы с целыми числами, их квадратами и кубами. In [17]: for х in ranged, 11): print ('{0:2d} {1:3d} {2:4d)'.format(x, x*x, x*x*x)) 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 9.2.3. Форматирование строк вручную Возьмем ту же таблицу квадратов и кубов, но отформатируем ее вручную. In [18] : for х in range (1, 11) : print(repr(x).rjust(2), repr(x*x).rjust(3), repr(x*x*x).rjust(4)) 1 1 1 2 4 8 3 9 27 4 16 64 5 25 125 6 36 216 7 49 343 8 64 512 9 81 729 10 100 1000 (Обратите внимание, что между столбцами появляется дополнительный пробел, т. к. функция print {) всегда добавляет пробел между аргументами.)
Ввод-вывод данных и работа с файлами | 211 Строковый метод rjusto выравнивает строку по правому краю в поле заданной ширины, заполняя строку пробелами слева. Похожим образом работают методы 1 just о и center о. Эти методы ничего не выводят на экран, а просто возвращают новую строку. Существует еще один метод zfilio, который дополняет строку нулями. В этом методе можно использовать плюсы и минусы. In [19]: |Out[19]: In [20]: |Out[2Q]: In [21]: '12'.zfill(5) '00012' '-12'.zfill(5) '-0012' '-3.14'.zfill(7) |Out[21]: '-003.14' In [22]: |Out[22]: '3.14159265359'.zfill(5) '3.14159265359' 9.2.4. Функции str() и repr() Функции str() и repro используются для получения строкового представления объекта. Обратите внимание на разницу результатов в приведенном примере. In [23]: s = 'Hello, Geeks.' print(str(s)) print(str (3.0/11.0)) Hello, Geeks. 0.2727272727272727 In [24]: s = 'Hello, Geeks.' print(repr(s)) print(repr(3.0/11.0)) 'Hello, Geeks.' 0.2727272727272727 Из выходных данных видно, что при использовании функции герг () строка выво­ дится в кавычках. Другие различия между этими функциями: ♦ Функция str () используется для создания вывода для конечного пользователя, а герг () в основном используется для целей отладки и разработки. Функция герг () дает однозначность, a str () — удобочитаемость. Например, если мы подозрева­ ем, что у числа с плавающей точкой есть небольшая ошибка округления, герг о покажет нам ее, a str () — нет. ♦ Функция герг о возвращает «формальное» строковое представление объекта (представление, которое содержит всю информацию об объекте), astro исполь-
212 | Глава 9 зуется для вывода «неформального» строкового представления объекта (более понятное с точки зрения пользователя). Давайте разберемся в этом на примере. In [25]: import datetime today = datetime.datetime.now() # удобочитаемый формат для объекта даты и времени print(str(today)) # официальный формат для объекта даты и времени print(repr(today) ) 2020-05-31 17:26:36.783561 datetime.datetime(2020, 5, 31, 17, 26, 36, 783561) Функция зователь. str о отображает дату и время таким образом, чтобы их мог понять поль­ Функция repr о печатает «официальное» представление объекта даты и времени (это означает, что с помощью этого представления мы можем реконструировать объект). 9.2.5. Старое форматирование строки Для форматирования строк также можно использовать оператор %. Левый аргумент интерпретируется как строка формата sprintf о, применяемая к правому аргументу, и оператор возвращает строку, полученную в результате операции форматирова­ ния. Например: In [26]: import math print('The value of pi is approximately %abs.' % math.pi) |The value of pi is approximately 3.141592653589793bs. In [27]: import math printf'The value of pi is approximately %.3f.' % math.pi) | The value of pi is approximately 3.142. 9.3. Чтение и запись файлов1 Метод open о возвращает файловый объект и чаще всего используется с двумя аргументами: f = open (имя_файла, режим') Первый аргумент— это строка, содержащая имя файла. Второй аргумент— это тоже строка, содержащая несколько символов, описывающих режим использования файла. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Ввод-вывод данных и работа с файлами | 213 Режим может состоять из: ♦ 'г' — файл открывается только для чтения; ♦ 'w' — файл открывается только для записи (если файл с таким же именем уже существует, он будет перезаписан); ♦ ' а' — файл открывается для добавления; любые данные, записываемые в файл, добавляются в его конец; ♦ ' г+ ’ — файл открывается как для чтения, так и для записи. Аргумент режима не является обязательным. Если он не указан, по умолчанию используется режим 'г'. Обычно файлы открываются в текстовом режиме, что означает, что вы читаете из файла и записываете в файл строки в определенной кодировке. При работе с файловыми объектами рекомендуется использовать ключевое слово with. Преимущество его использования заключается в том, что файл правильно закрывается после завершения работы, даже если в какой-то момент возникнет ис­ ключение. with open(’workfile') as f: read_data = f.readO Если вы не используете ключевое слово with, то в конце нужно вызвать метод f.close(), чтобы закрыть файл и высвободить все используемые им системные ресурсы. 9.3.1. Методы файловых объектов Во всех примерах этого раздела предполагается, что файловый объект с именем уже создан. f Чтобы прочитать содержимое файла, вызовите метод f.read(size), который считы­ вает size символов (в текстовом режиме) или size байт (в бинарном режиме). Здесь size — необязательный числовой аргумент. Если размер опущен или указано отри­ цательное значение, будет прочитано и возвращено все содержимое файла, но если размер файла вдвое превышает объем памяти вашей машины — у вас будут про­ блемы. Если достигнут конец файла, f.readO вернет пустую строку (''). »> f.readO # если файл состоит из одной строки |'This is the entire file.Xn' »> f.readO Метод f. readline () читает одну строку из файла. При каждом вызове метода чита­ ется следующая строка. >» f.readline() # файл состоит из двух строк I'This is the first line of the file.Xn'
214 | Глава 9 »> f.readline() | 'Second line of the file.\n' »> f.readline() Для последовательного чтения строк из файла вы можете использовать цикл. Это эффективно с точки зрения памяти, быстро, и код будет простым. »> for line in f: print(line, end='') This is the first line of the file. Second line of the file. Если вы хотите извлечь все строки файла в список, вы можете использовать функ­ цию list(f) ИЛИ метод f .readlines(). Метод f. write (string) записывает содержимое строки в файл, возвращая количество записанных символов. »> f.write('This is a test\n') I15 Другие типы объектов перед записью необходимо преобразовать — либо в строку (в текстовом режиме), либо в байтовый объект (в бинарным режиме). »> value = ('the answer', 42) »> s = str (value) # преобразование кортежа в строку »> f. write (s) I18 z 9.3.2. Создание файла и запись в него Мы рассмотрели, как открывать, читать и записывать файлы на Python. Давайте теперь разберем очень простой пример. Мы создадим файл, запишем в него текст, закроем файл, а затем откроем его, чтобы прочитать содержимое. In [28]: # строковая переменная с произвольным текстом story = ' '' Lets write a small story. There was a curious student. He wanted to learn Python. His age was... Well, how does it matter. One can be student at any age. Lets say, he was a good student and within a short time, learnt all about programming and python. He combined that with his business acumen, and became a good data scientist.'1' # создание нового текстового файла f = openCsmall_story.txt", "w") Выполнив последнюю строку кода, мы создали новый файл с именем small_ story.txt. Вы можете зайти в свою базовую папку и убедиться в этом сами. Сейчас это пустой файл, потому что мы еще ничего не записали в него.
Ввод-вывод данных и работа с файлами | 215 Теперь выполним запись в файл. Воспользуемся текстом, который мы только что написали, и сохраним этот текст в только что созданный нами файл. In [29]: # запись текстовой переменной story в файл f f.write(story) # |Out[29]: In [30]: получаем количество символов, записанных в файле f 330 f.close() 9.3.3. Открытие файла и чтение его содержимого Интересно, что один и тот же метод создает пустой файл, а также открывает файл для чтения. Единственная разница, если вы заметили, заключается в режиме ис­ пользования файла. In [31]: # по умолчанию файл открыт только для чтения f = openCsmall_story.txt", In [32]: 'г') # простой вызов переменной не выводит на экран текст из файла, # а только информацию о файловом объекте |Out[32]: f <io.TextIOWrapper name-'small story.txt' mode='r' encoding='cp!252'> Чтобы прочитать содержимое файла, используйте метод In [33]: read (). f.read() Out[33]: '\nLets write a small story.\nThere was a curious student. He wanted to learn Python.\nHis age was... Well, how does it matter. One can be student at any age.XnLets say, he was a good student and within a short time, learnt all aboutXnprogramming and python. He combined that with his business acumen, and becameXna good data scientist.' Мы также можем сохранить содержимое файла в переменную. 9.3.4. Построчное чтение Мы можем прочитать содержимое файла построчно. In [34]: f = openCsmall_story.txt") |Out[34]: f .readline () '\n' In [35]: |out[35]: f.readlineO 'Lets write a small story.\r7 In [36]: | Out [36]: f.readline(12) 'There was a~
216 | Глава 9 Метод readline () возвращает следующую строку из файла. Если мы передадим в этот метод число, он вернет указанное количество символов из следующей строки. 9.3.5. Чтение и запись нетекстовых файлов Описанные методы хорошо подходят для текстовых файлов. Но все же этого не­ достаточно для других типов файлов, которые могут вам встретиться. И вот тут-то и открывается вся сила языка Python, которой не хватает многим другим языкам. У Python есть открытый исходный код, и множество умных людей постоянно улучшают его и создают новые модули на все случаи жизни. Ну, или почти на все. Для обработки, чтения и записи файлов существуют различные модули, которые делают нашу работу проще и интереснее. В главе 17 мы изучим модуль Pandas. Эта библиотека — одна из наиболее часто ис­ пользуемых программистами и специалистами по данным, работающими с Python. 9.4. Резюме В этой главе мы рассмотрели, как вывести результаты работы кода на экран. Мы научились элегантно и эффективно оформлять вывод. Далее мы увидели, как соз­ давать текстовые файлы из среды Python, а затем записывать в них данные. Часто бывает очень полезно иметь возможность сохранения вывода или результата в от­ дельном текстовом файле, который можно сохранять, читать и распространять за пределами среды Python. Однако в этой главе мы ограничились лишь текстовыми файлами, пообещав себе, что рассмотрим остальные полезные типы файлов позже с помощью библиотеки Pandas. Манипуляции со строками и вывод в файл очень пригодятся в вашей работе. 9.5. Упражнения 9.5.1. Ответьте на вопросы 1. Что делает функция input () ? 2. Как отформатировать строки с помощью метода format () ? 3. Как ограничить размер считываемого файла на Python? Почему это важно? 4. Зачем нам нужно открывать сторонние файлы в Python? 5. Следующий код предназначен для создания файла, в котором хранится список слов. Какое будет имя у этого файла на жестком диске? file = open('textfile.txt', 'w') word = 1' while word.upper!) != 'END': word = raw_input(1 Enter a word use END to quit') file.write(word + '\n') file.close()
Ввод-вывод данных и работа с файлами 6. сравните работу методов сходство и различие? 7. Сравните методы личия? write о read о, readline () и writelines (). И readlines (). read () 10. В чем разница между функциями и readline о str о и 217 В чем между ними В чем между ними сходства и раз­ 8. Какие режимы можно использовать с функцией 9. Объясните работу методов | open о при открытии файла? на примерах. repr о? 9.5.2. Правда или ложь 1. Строковое приглашение в функции input является обязательным. 2. Функция input () всегда возвращает строку. 3. Функция 4. Метод input о format () принимает в качестве входных данных только строки. использует фигурные скобки {} как заполнители. 5. Если в методе format!) используются именованные аргументы, на их значения можно ссылаться, используя имя аргумента. 6. Порядок объектов в форматируемой строке изменить нельзя. 7. Функция str () 8. Аргументы 'г' используется для строк, а и 'г+' функции open!) герг() —для чисел. выполняют одну и ту же функцию. 9. В Python мы можем открывать только существующие файлы, а создавать новые файлы нельзя. 10. В Python можно читать только текстовые файлы. 9.5.3. Практические задания 1. Напишите код, который принимает число от пользователя, а возвращает квадрат введенного числа. 2. Попросите у пользователя ввести его возраст в качестве входных данных. Вы­ чтите его возраст из текущего года, чтобы узнать год рождения пользователя. Результат выведите в формате «Яродился в ... году». 3. Напишите функцию, которая принимает три аргумента: входной файл, выход­ ной файл и функцию преобразования. Первый аргумент— это файл, открытый для чтения, второй аргумент — это файл, открытый для записи, а третий аргу­ мент— это функция преобразования, которая принимает строку на вход, вы­ полняет какое-то преобразование по вашему выбору и возвращает измененную строку. Основная функция должна читать строку из входного файла, выполнять над ней функцию преобразования, а затем записывать измененную строку в вы­ ходной файл. Преобразование может быть, например, таким: каждое слово в строке должно начинаться с заглавной буквы.
218 | ГлаваЭ 4. Напишите функцию для создания текстового файла, содержащего следующие данные: The 344-sq. km. the periphery of Navi Mumbai starts on the East with Kalundre village, on the West is the hill range that starts from Digha and runs up to Taloja; in the North is Digha village while Chanje village lies in the South, Dronagiri is on the South-East. The area comprised of 95 villages of Thane and Raigad Districts. а) Прочтите все содержимое файла с помощью метода отобразите его на экране. read о или readlines () и б) Добавьте в файл любой текст на свое усмотрение и выведите содержимое файла с номерами строк. в) Выведите последнюю строку файла. г) Выведите первую строку, начиная с 10-го символа. д) Попросите пользователя указать номер строки из файла, которую нужно про­ читать. 5. Напишите программу, которая принимает от пользователя имя файла и отобра­ жает все строки из файла, которые содержат символ комментария Python 6. Читать файл с начала— это просто, но что если вам нужно прочитать файл в обратном направлении, например для чтения файлов с логами. Напишите про­ грамму для чтения и отображения содержимого файла от конца до начала. 9.5.4. Изучите самостоятельно 1. Откройте несколько небольших текстовых файлов на Python. Попрактикуйтесь в использовании функций, которые вы изучили в этой главе. 2. Напишите небольшое эссе в ячейке Markdown в Jupyter Notebook. Сохраните его в виде текстового файла.
10 ПРОЕКТ 2: Автоматизация обработки множества изображений Мы изучаем нюансы языка программирования. На этом языке мы общаемся с ком­ пьютером. А зачем нам вообще общаться с компьютером? Чего мы добиваемся? Компьютеры широко используются из-за того, что по сравнению с людьми они: ♦ работают быстрее; ♦ лучше справляются с повторяющимися задачами. Им не становится скучно, и они не ошибаются (по своей вине, во всяком случае). И именно поэтому, а также по многим другим причинам, мы используем языки программирования вроде Python. А теперь давайте решим одну реальную проблему, с которой мы можем так или иначе столкнуться в жизни. Нам бы хотелось иметь волшебную палочку, которая бы легко выполняла за нас скучную и повторяющуюся работу. Я покажу вам, как Python со всеми его библиотеками и модулями может стать для вас этой самой палочкой-выручалочкой. Допустим, вы с одногруппниками ездили в горный поход. Вы видели заснеженные горы и пышные зеленые долины. Склоны гор были усеяны стадами коз и овец. Вдоль долины протекала река. Вода была настолько прозрачной, что в ней было видно рыбу и гальку на дне. Восхитительное место. Вы постоянно все фотографировали с помощью своей циф­ ровой камеры, пока не закончилось место на основной карте памяти и на запасных. Довольный своими навыками фотографа и красотой вокруг, вы вернулись домой. Вы заряжены позитивом и хотите рассказать, в каком прекрасном месте вы побы­ вали. Вы включаете свой компьютер и копируете все фотографии с карт памяти. Теперь нужно поделиться фотографиями со своими друзьями в социальных сетях, со своими подписчиками в блоге, а также разместить их на своем веб-сайте. И тут-то вы понимаете, что вам предстоит выполнить очень много работы. Почему? ♦ Фотографии много весят (от 2 до 40 Мб каждая, а иногда и больше). ♦ У многих фотографий неправильная ориентация, и вам нужно повернуть их, чтобы они были понятны зрителю. ♦ В свой блог вы можете загружать фотографии только определенного формата (например, png), а ваши фотографии имеют формат jpg.
220 | Глава 10 ♦ Многие фотографии будут потрясающе смотреться в черно-белом варианте, особенно фото на длинной выдержке и пейзажи. ♦ Разрешение изображений jpg не соответствует требованиям принтера. У вас на компьютере есть инструменты для выполнения всех этих задач, но вам нужно выполнить все эти преобразования для каждой фотографии. Как насчет того, чтобы позвать компьютер на помощь? Нам известно, что компью­ тер не против выполнять монотонную работу. Более того, теперь вы знаете, как с ним разговаривать, т. е. знаете его язык. Вы знаете Python. Итак, давайте напишем несколько строк кода, чтобы компьютер мог выполнить все нужные нам преобра­ зования всех фотографий в папке. Да, вы не ослышались. Всех сразу. Для этого нам достаточно сохранить нужные фотографии, над которыми вы хотите выполнить определенную операцию, в одной папке. По мере выполнения этого проекта вы увидите, что такой способ дает вам гораздо больше гибкости, чем использованные ранее инструменты. Мы будем работаться с двумя библиотеками Python. Первая — это Pillow, библио­ тека для работы с изображениями, а вторая — os, библиотека для взаимодействия с операционной системой. Pillow— это новая версия библиотеки PIL (Python Imaging Library), которая добавляет возможности обработки изображений в ваш интерпретатор Python. In [1]: from PIL import Image import os # абсолютный путь к текущему рабочему каталогу In [2]: os.getcwdf) Out [ 2]: ’С:\\Users\\nilabhnishchhal\\PYTHON_BOOK_NILABH\\Proj ect2_ Automating Multiple Photo processing' Модуль os в Python помогает напрямую взаимодействовать с операционной систе­ мой. Он пригодится нам, когда мы будем обращаться к нескольким файлам в опре­ деленной папке. Pillow позволяет работать с изображениями и манипулировать ими. Мы будем ис­ пользовать библиотеку Pillow вместе с другими функциями Python. Это поможет выполнить над выбранными нами фотографиями определенные действия, например открыть, изменить размер, повернуть, изменить цвета, а также сохранить обратно в +папку. Файлы изображений, с которыми я буду работать, находятся в той же папке, что и мой файл Jupyter, который я запускаю. Это позволит мне избежать необходимости постоянно указывать полный путь к файлам изображений (рис. 10.1). In [3]: imagel = Image.openCpicl.jpg") image1 Если вы хотите открыть файл изображения вне документа Jupyter, используйте метод imagel. show ().
Проект 2: Автоматизация обработки множества изображений | 221 Рис. 10.1. Открытие изображения в Jupyter Notebook 10.1. Изменение типа файла (расширения) Сохранить файл изображения в другом формате легко: In [4]: imagel.save("picl.png") Но это для одного изображения, а нам нужно сделать то же самое с несколькими файлами. Для этого мы будем использовать модуль os, который позволит обра­ щаться к файлам в папке. Получив список всех файлов, мы проверим, есть ли там файлы, с которыми мы хотим работать, или нет. Здесь мы применим один из самых удобных трюков в программировании — старые добрые циклы. Мы определим тип файла по его расширению и переберем все такие файлы (с одинаковым расширени­ ем или одного типа). In [5]: # поиск всех файлов и папок в текущем рабочем каталоге os.listdir() Out[5]: ['.ipynb_checkpoints1, 'b&w', 'dpi_300', 'image2.jpg',
222 | Гпава 10 'image3.jpg', 'NewExtnsn', 'picl.jpg', 'picl.png', 'picl300.jpg', 'pic2.jpg', 'pic3.jpg', 'pic4.jpg', 'pic5.jpg', 'Project - Automating task of Multiple image processing.ipynb', 'resize', 'rotate'] In [6]: # перебор файлов изображений в цикле for f in os.listdir("."): if f.endswithf.jpg"): print(f) image2.jpg image3.jpg picl.jpg picl300.jpg Pic2.jpg pic3.jpg pic4.jpg pic5.jpg Этот цикл позволяет получить все файлы в каталоге, которые имеют определенное расширение. Таким образом, мы можем перебрать все файлы одного типа, которые нужно обработать. Теперь, когда мы можем получить доступ ко всем файлам изображений, выделим в них имя и расширение. Это можно сделать с помощью метода os.path.splitextO, который разделяет имя и расширение файла. In [7]: for f in os.listdir("."): if f.endswithC.jpg"): i = Image.open(f) fn, fext = os.path.splitext(f) print(fn, fext) image2 & .jpg image3 & .jpg picl & .jpg picl300 & .jpg pic2 & .jpg pic3 & .jpg pic4 & .jpg pic5 & .jpg Теперь, когда мы разделили имя и расширение, мы можем сохранить файлы с та­ кими же именами и новым расширением.
Проект 2: Автоматизация обработки множества изображений In [8]: | 223 for f in os.listdir("."): if f.endswithC.jpg"): i = Image.open(f) fn, fext = os.path.splitext(f) i.save("NewExtnsn/{}.pdf".format(fn) ) Что делает строка "NewExtnsn/{} .pdf"? Вспомните тему о форматировании вывода. Мы использовали этот способ, чтобы создать имена новых файлов и поместить их в папку с именем NewExtnsn. Вам необходимо сначала создать эту новую папку в вашем рабочем каталоге, а затем использовать ее имя в адресе. Я создал папку с именем NewExtnsn. В этой главе для каждого преобразования мы создаем новые файлы в отдельных папках. После создания файлов обращаться к ним можно будет таким же образом, как описано выше. 10.2. Изменение размеров фотографий Мы можем задать новый размер изображения, а также менять соотношение сторон. Давайте создадим еще одну папку внутри рабочего каталога и назовем ее resize. Внутри этой папки у нас будет еще две вложенные папки. Нам требуется получить фотографии для двух разных целей: одну — для публикации на веб-странице, дру­ гую — в качестве миниатюры фотографии. Поэтому я сохраню эти варианты в от­ дельных папках. Назовем папки small и tiny. thumbnail () — это метод, используемый для изменения размера, а его аргумент — кортеж нужного нам размера. In [9]: size_small = (600,600) size_tiny = (200,200) for f in os.listdir("."): if f.endswith(".jpg"): i = Image.open(f) fn, fext = os.path.splitext(f) i.thumbnail(size_small) i.save("resize/small/{}_small{}".format(fn, fext)) i.thumbnail(size_tiny) i.save("resize/tiny/{}_tiny{format(fn, fext)) 10.3. Преобразование изображений в черно-белые Библиотека Pillow содержит множество разных функций для преобразования изо­ бражений. Мы не будем рассматривать их все, но сейчас я покажу, как преобразо­ вать цветное изображение в черно-белое.
224 | Глава 10 In [10]: imagel.convert(mode='L').save("image2.jpg") In [11]: Image2 Image2 = Image.open("image2.jpg") Чтобы перевести все изображения из текущего каталога в черно-белые, создайте сначала вложенную папку b&w. In [12]: for f in os.listdir: if f.endswith(".jpg"): i = Image.open(f) fn, fext = os.path.splitext(f) im = i.convert(mode = 'L') im.save("b&w/{}_bw{)".format(fn, fext)) 10.4. Поворот изображений Мы делаем фотографии как с портретной, так и с пейзажной ориентацией. Часто при копировании с фотоаппарата изображения сохраняются с неправильной ориен­ тацией. Поэтому мы меняем ее при просмотре фотографий, а потом, когда мы за­ крываем окно, фотографии остаются в исходной ориентации, заставляя нас делать то же самое в следующий раз при просмотре или использовании в презентации или коллаже. Предположим также, что вы хотите повернуть изображения на произвольный угол, например, на 55 или 120°. Не все редакторы изображений позволяют это делать, а даже если и позволяют, то выполнять это для всех файлов утомительно. С помощью метода rotate () мы можем повернуть изображение на любой угол, как показано в примере ниже (вывод результата — на рис. 10.2). In [13]: # поворот изображения на 55° imagel.rotate(55).save(”image3.jpg") Image3 = Image.openfimage3.jpg") In [14]: Image3 Поворот всех изображений на 90° и сохранение их в новой вложенной папке rotate будет выглядеть следующим образом. In [15]: for f in os.listdir("."): if f.endswithC.jpg"): i = Image.open(f) fn, fext = os.path.splitext(f) im = i.rotate(90) im.save("rotate/{}_rot{}".format(fn, fext))
Проект 2: Автоматизация обработки множества изображений | 225 Рис. 10.2. Поворот изображения 10.5. Изменение разрешения изображения Что такое разрешение и зачем оно нужно? Разрешение — это количество точек на дюйм (DPI), с технической точки зрения этот параметр соответствует количеству точек на дюйм при печати на принтере. Сегодня этот термин часто используют неправильно, имея в виду параметр PPI, что означает количество пикселей на дюйм изображения. Поэтому, когда кто-то гово­ рит, что ему нужна фотография с разрешением 300 dpi, имеется в виду 300 ppi. Возникает очевидный вопрос: зачем менять разрешение изображения? Приведу вам понятный пример из реальной жизни. В процессе написания этой кни­ ги, чтобы сделать ее более интересной и легкой для понимания, я использовал мно­ го поясняющих изображений. Когда я отправлял электронную копию книги своему издателю, он сказал, что качество изображений слишком низкое, а для печати тре­ бовались изображения с разрешением не менее 300 dpi. И тут возникла проблема. Некоторые веб-сайты позволяют обрабатывать изобра­ жения по одному, если используется бесплатная версия. Кроме того, есть программное обеспечение, которое умеет это делать, но, опять же, обрабатывать приходится все изображения вручную по одному. В этой книге около 200 изо­ бражений, и менять dpi одного за другим было бы кошмаром. Тогда Python снова пришел мне на помощь. Библиотека Pillos и всего несколько строк кода — и страшная задача была выполнена за несколько секунд.
226 | Глава 10 И для этого даже не потребовалось писать отдельный метод. При сохранении изо­ бражения с помощью метода save () вы можете указать значение dpi, передав кор­ теж в качестве именованного аргумента, и все готово. In [16]: for f in os.listdir("."): if f .endswithf. jpg"): i = Image.open(f) fn, fext = os.path.splitext(f) i.save("dpi_300/{}_dpi_300{}".format(fn, fext), dpi = (300,300)) 10.6. Резюме В этом проекте я попытался познакомить вас с двумя важными моментами. Первый достаточно очевидный — это то, как использовать библиотеки Pillow и os приме­ нительно к задаче обработки изображений. Самое полезное здесь то, что мы научи­ лись использовать циклы для перебора файлов определенного типа и вносить в них изменения. То же самое можно делать с любыми другими файлами. Разделение имени файла и его расширения можно выполнять и для других типов файлов, а также применять к ним аналогичные операции. Второй неявный момент в этом проекте заключался в том, чтобы показать вам, что можно использовать Python для автоматизации рутинных или повторяющихся за­ дач. Такие задачи могут иметь, а могут и не иметь прямого решения, но если вы настойчивы и пытливы, то в вашем распоряжении достаточно ресурсов, чтобы най­ ти выход. Вы можете воспользоваться разными уроками из этой книги, поискать похожие задачи в Интернете или, как мы уже обсуждали ранее, задать свой вопрос на сайте https://stackoverflow.com/. Важно, чтобы компьютеры работали на вас. Автоматизируйте рутинные задачи! 10.7. Изучите самостоятельно 1. Подумайте о своих повседневных задачах, которые, по вашему мнению, можно полностью или частично автоматизировать с помощью программирования. 2. Составьте список таких задач и выберите ту, которая вам докучает больше дру­ гих. Попробуйте автоматизировать ее с помощью Python. 3. Сделайте решение этой задачи своим проектом. Это будет самый быстрый спо­ соб выучить не только Python, но и овладеть искусством программирования в целом.
11 Классы 11.1. Основные понятия Классы предоставляют способ объединения данных и функциональности. Создание нового класса — это, по сути, создание нового типа объектов, с помощью которого в дальнейшем вы можете создавать новые объекты (экземпляры класса). У каждого экземпляра класса могут быть атрибуты, хранящие информацию о его состоянии. Экземпляр класса также может иметь методы (определенные в его классе), которые позволяют менять состояние экземпляра'. Не кажется ли вам, что это определение какое-то слишком сложное? Но с ним все в порядке. Мы разберемся со всем этим последовательно, шаг за шагом. Но перед этим давайте посмотрим, для чего вообще нужны классы. Они помогают програм­ мисту использовать парадигму объектно-ориентированного программирования в Python. Их польза станет более очевидной, когда мы углубимся в тему. 11.1.1. Введение в объектно-ориентированное программирование Python поддерживает разные подходы к программированию. Во всех программах, которые мы писали до сих пор, мы строили нашу программу вокруг функций, т. е. блоков кода, которые манипулируют данными. Это процедурно-ориентированное программирование. В этом случае мы организовываем программу в виде пошаговой схемы или рецепта. Части программы выполнены в виде блоков кода и функций (рис. 11.1), которые выполняются в нужной последовательности для выполнения определенной задачи. Рис. 11.1. Процедурно-ориентированное программирование 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
228 | Глава 11 В большинстве случаев легко использовать именно этот подход, но при написании больших программ или в случае, когда удобнее оперировать объектами, лучше ис­ пользовать другой подход— объектно-ориентированное программирование'. Это один из самых популярных подходов к решению задач программирования — соз­ дание объектов. Объектно-ориентированное программирование (ООП) — это парадигма програм­ мирования, в которой программу структурируют таким образом, чтобы данные и функциональность объединялись в отдельные объекты (рис. 11.2). Рис. 11.2. Объектно-ориентированное программирование Рис. 11.3. Основные понятия и принципы ООП Другими словами, ООП — это подход к моделированию в программе конкретных реальных объектов, таких как автомобили, а также отношений между разными объ­ ектами, например студент и колледж, игрок и тренер и т. д. В ООП объекты реаль­ ного мира моделируются как объекты программы. Эти объекты хранят некоторые ассоциированные данные и могут выполнять определенные действия. У объекта есть две характеристики: атрибуты и поведение. Например, у класса «Человек» могут быть такие атрибуты, как имя, возраст, рост, вес, адрес и т. д., а его поведение — это ходить, разговаривать, спать, есть и т. д. Основные понятия и принципы, используемые в ООП, приведены на рис. 11.3. И мы кратко познакомимся с ними далее. 1 Swaroop, 2003 (https://python.swaroopch.com/) [39].
Классы | 229 11.1.2. Введение в понятие класса Как мы уже знаем, все в Python является объектом. Встроенные структуры данных Python (число, строка, список и т. д.) предназначены для представления простых данных, таких как имя человека, возраст, зарплата ит. д. А что, если мы хотим смоделировать что-то более сложное? Например, более цело­ стное представление о человеке, включая его имя, возраст, зарплату, образование и номер трудовой книжки. Мы можем создать список, в котором все эти сведения будут храниться вместе, например ["Nilabh", 34, 50000, graduate, 9469]. Но это лишь один человек. А что делать, если у нас есть такие данные о 100 со­ трудниках компании? Как проверить, у всех ли указан возраст и квалификация? Что если мы захотим добавить к этой информации какие-то другие атрибуты? Что если мы хотим выполнить какое-то действие над всей этой информацией о сотруд­ никах? Связанные по смыслу данные необходимо объединить в одно целое. Именно это и делают классы. Классы используются для создания новых пользовательских структур данных, со­ держащих информацию о чем-либо. В упомянутом выше случае мы можем создать класс Employee для работы с информацией обо всех сотрудниках компании, а также для выполнения над ними некоторых действий или функций. Важно отметить, что класс — это лишь структура данных или шаблон, показываю­ щий, как что-то должно быть определено, но самих данных в классе не содержится. Класс Employee может указывать на то, что для сотрудника нужно знать его имя, квалификацию и возраст, но сам класс не хранит имя, квалификацию или возраст конкретного сотрудника. Помните, что класс — это всего лишь шаблон. Вообще говоря, внутри класса есть два типа объектов: ♦ объекты экземпляров; ♦ объекты методов. Объекты экземпляров можно понимать как имеющиеся атрибуты. Объекты методов можно понимать как имеющееся поведение. Но это просто аналогия, а не техническое определение. Как только вы хорошо пой­ мете концепцию, придет и более глубокое понимание. Но, чтобы упростить обуче­ ние, вы можете постепенно продвигаться вместе со мной, помня эти аналогии. 11.2. Объект класса Класс — это шаблон объектов. И класс сам по себе тоже является объектом в Python. Можно представить класс как пустой бейдж сотрудника (рис. 11.4). На бейдже есть информация об имени, контактном номере, отделе, возрасте, идентификаторе со-
230 | Глава 11 трудника и т. д. На основе этих данных мы можем больше узнать о сотруднике. Здесь сотрудник — это объект. Можно также считать, что класс — это представление о каком-то реальном объекте. Пустой бейдж эквивалентен классу. В компании будут сотни сотрудников с запол­ ненными бейджами. Их данные будут организованы в класс Employee. Удостоверение сотрудника Компания: Python Enterprises Отдел: Дата рождения: Номер телефона: Вызов экстренной помощи: ИМЯ ФАМИЛИЯ ID сотрудника: Подпись Рис. 11.4. Класс на примере бейджа сотрудника Создать новый объект класса в Python очень просто. Чтобы создать класс с именем Employee, просто запустите следующие две строки кода: In [1]: class Employee: pass Здесь для определения пустого класса Employee мы используем ключевое слово class. На основе класса мы создаем экземпляры. Экземпляр — это конкретный объ­ ект, созданный из определенного класса. Теперь мы можем создавать экземпляры класса Employee. Мы создали пустой класс, и на шаблон он пока не похож, потому что в нем нет ни­ чего, что позволило бы отличить один экземпляр от другого. Предположим, у нас есть данные о двух сотрудниках по имени Нилаб и Сандип. Теперь посмотрим, как создать класс и экземпляры класса. 11.2.1. Метод_ init__ Давайте определим метод_ In [2]: init_ в классе Employee: class Employee: # атрибут класса (общий для всех экземпляров класса) company = "Python Enterprises" # атрибуты экземпляра def__ init__ (self, name, age, dept): self.name = name self.age = age self.department = dept
Классы | 231 Вы должны были заметить, что у класса появились атрибуты, такие как имя, воз­ раст и отдел сотрудника. Теперь этот класс выглядит как шаблон, в котором у всех сотрудников есть атрибуты. Метод_ init__ запускается в момент, когда создается объект экземпляра класса. Этот метод нужен для инициализации создаваемого объекта (например, для пере­ дачи вашему объекту начальных значений). Обратите внимание на двойное под­ черкивание в начале и в конце имени метода. Теперь, когда мы создали класс, мы создадим экземпляры класса или, другими сло­ вами, копии объектов по готовому шаблону. 11.3. Объекты экземпляров Если класс является шаблоном, то экземпляр класса — это копия класса с заданны­ ми значениями, т. е. готовый объект, принадлежащий определенному классу. Это больше не абстрактная идея, а настоящий сотрудник, например, с именем Нилаб и идентификатором 9469 (рис. 11.5). Удостоверение сотрудника Компания: Python Enterprises Отдел: Производство Дата рождения: 01.01.1998 Номер телефона: 9898989898 Вызов экстренной помощи: 100 имя ФАМИЛИЯ ID сотрудника: 9468 Нилаб Нишчхал Подпись Рис. 11.5. Экземпляр класса — сотрудник Нилаб Итак, как мы поняли, класс— это пустой шаблон. Он определяет необходимую информацию. После заполнения шаблона получается экземпляр класса, который содержит реальную информацию. Вы можете заполнить несколько копий шаблона для создания множества экземпля­ ров, но если бы шаблон не был определен изначально, вы не знали бы, какую информацию требуется указать. Следовательно, прежде чем создавать отдельные экземпляры класса, вы должны сначала задать, что именно вам нужно, путем опре­ деления класса. Теперь посмотрим, как создать объекты экземпляров класса. 11.3.1. Создание экземпляров класса Чтобы создать объекты для двух уникальных сотрудников, выполните: In [3]: # создание экземпляров класса Employee nilabh = Employee("Nilabh", 22, "Production") sandip = Employee("Sandip", 28, "Marketing")
232 Глава 11 | Здесь мы создали два экземпляра класса Employee. Экземпляр класса создать очень просто: имя_экземпляра = имя_класса (аргументы) 11.3.2. Как это работает Все объекты экземпляров класса содержат атрибуты (или характеристики). Мы ис­ пользуем метод __init__ для инициализации начальных значений атрибутов экзем­ пляров класса. Для этого в метод и передаются соответствующие параметры. В случае с нашим классом Employee у каждого сотрудника есть имя, возраст и отдел, которые необходимо знать при создании сотрудника. У метода также есть первый параметр self, который указывает на сам объект. С помощью self можно обращаться к атрибутам и методам создаваемого экземпля­ ра класса. Примечание Вызывать метод вручную не требуется, т. к. он автоматически вызывается при создании нового экземпляра Employee. Хотя атрибуты экземпляров специфичны для каждого объекта, атрибуты самого класса одинаковы для всех экземпляров. В нашем случае это название компании, т. к. все сорудники работают в одной и той же компании. 11.3.3. Пример использования экземпляров класса Давайте объединим создание класса и экземпляров вместе и посмотрим, что можно с ними делать. In [4] : class Employee: # атрибут класса (общий для всех экземпляров класса) company = "Python Enterprises" # атрибуты экземпляра def __ init__ (self, name, age, dept): self.name = name self.age = age self.department = dept # создание экземпляров класса Employee nilabh = Employee("Nilabh", 22, "Production") sandip = Employee("Sandip", 28, "Marketing") # обращение к атрибутам экземпляров print("{} and {} are two employees of {) company.".format) nilabh.name, sandip.name, Employee.company))
Классы print("{} is {} and works in (} department of | 233 format( nilabh.name, nilabh.age, nilabh.department, nilabh.company)) print("{} is {} and works in {} department of {}.".format ( sandip.name, sandip.age, sandip.department, sandip.company)) Nilabh and Sandip are two employees of Python Enterprises company. Nilabh is 22 and works in Production department of Python Enterprises. Sandip is 28 and works in Marketing department of Python Enterprises. Мы создали новый экземпляр класса Employee, присвоили его переменной nilabh и передали ему три аргумента, Nilabh, 22 и Production, которые соответствуют имени, возрасту и отделу этого сотрудника. Затем эти аргументы передаются методу_ init__ , который вызывается каждый раз, когда мы создаем новый экземпляр класса, чтобы назначить объекту имя, возраст и отдел. Вам может быть любопытно, почему при создании новых экземпляров клас­ са не пришлось передавать аргумент self. Это и есть магия Python. Когда мы создаем новый экземпляр класса, Python авто­ матически определяет, что такое self (в данном случае сотрудник), и передает его методу_ init__ . После создания объекта экземпляра класса мы можем обращаться к его атрибутам. Синтаксис выглядит как имя_экземпляра. атрибут. Кроме того, в приведенном выше примере вы можете заметить, что в первом выво­ де значение Employee.company содержит ТОТ же результат, ЧТО И nilabh.company и sandip.company в следующих двух выводах. Это потому, что company является атрибу­ том класса Employee и, следовательно, автоматически передается всем экземплярам этого класса. Он общий для всех объектов экземпляров. Но атрибуты экземпляров, которые мы передаем в качестве аргументов при их создании, такие как имя, воз­ раст и отдел, специфичны для каждого экземпляра класса. Здесь, после того как мы создали экземпляры класса Employee, т. е. nilabh и sandip, мы использовали функцию print!) для генерации текстовой строки, которую мы написали отдельно, вне определения класса (обратите внимание на отсутствие отступа перед функцией print о). Что будет, если мы просто выведем экземпляр как есть? In [5]: print(nilabh) < main__ .Employee object at 0x000001E183BC8208> Результат, как вы видите, вообще не информативный. Выводится только тип объек­ та и его адрес в памяти. Но мы можем сделать вывод более интересным с помощью встроенного метода классов. Как мы видели ранее, функция dir о с переданным ей именем класса (например, позволяет вывести все встроенные методы. Мы буквально только что dir (Employee))
234 | Глава 11 использовали один из них для инициализации класса (_ init__ ). Есть и другой встроенный метод _str__ , который возвращает строковое представление объекта. Давайте посмотрим, как он работает, и если вы возьмете за привычку начинать соз­ дание класса с _ init__ и_ str__ , это может пригодиться в будущем. In [б]: class Employee: # атрибут класса (общий для всех экземпляров класса) company = "Python Enterprises" # атрибуты экземпляра def __ init__ (self, name, age, dept): self.name = name self.age = age self.dept = dept def __ str__ (self) : return "My name is {}, my age is {} and I work in {} department of {}.".format(self.name, self.age, self.dept, self.company) # создание экземпляров класса Employee nilabh = Employee("Nilabh ", 22, "Production") sandip = Employee("Sandip", 28, "Marketing") In [7]: print(nilabh) My name is Nilabh, my age is 22 and I work in Production department of Python Enterprises. 11.4. Объекты методов Методы — это функции, определенные внутри тела класса. Они используются для определения поведения объекта. Мы определим метод в том же классе, который использовали ранее. Метод сооб­ щит нам год рождения сотрудника в зависимости от его возраста (который является атрибутом экземпляра) и текущего года (который является параметром метода). In [8]: class Employee: # атрибут класса (общий для всех экземпляров класса) company = "Python Enterprises" # атрибуты экземпляра def __ init__ (self, name, age, dept): self.name = name self.age = age self.department = dept
Классы # | 235 создание объекта метода def YOB(self, current_year): return current_year - self.age # создание экземпляра класса Employee nilabh = Employee("Nilabh ", 22, "Production") print("Nilabh was born in {}.".format(nilabh.YOB(2020))) [Nilabh was born in 1998. Как вы могли заметить, метод yob о определяется так же, как пользовательская функция. Однако разница заключается в синтаксисе вызова. В этом и заключается основное различие между функцией и методом. Здесь метод находится внутри класса Employee и, следовательно, не является гло­ бальным методом, а вызывается только на экземпляре этого класса. 11.5. Наследование Наследование — это мощный принцип объектно-ориентированного программиро­ вания. Его значение следует из названия — объект может что-то наследовать от родителя. В данном случае дочерний класс наследует атрибуты и методы от своего родитель­ ского класса. Наследование позволяет определить новый класс, внеся небольшие изменения в существующий класс или даже без них. Новый класс называется производным (или дочерним) классом, а тот, от которого он наследуется, называется базовым (или родительским) классом (рис. 11.6). Наследование считается одним из наиболее важных аспектов ООП, поскольку оно позволяет избегать повторений в коде и делает код более надежным. Рис. 11.6. Наследование классов в Python Синтаксис наследования в Python: class Базовый_класс: Тело базового класса class Производный_класс(Базовый_класс) : Тело производного класса
236 | Глава 11 Наследование позволяет нам определить класс, который перенимает функциональ­ ность от родительского класса. Мы также можем добавить производному классу дополнительный функционал. У наследования есть много преимуществ. ♦ Наглядно отображает отношения в реальном мире. ♦ Обеспечивает возможность повторного использования кода. Нам не приходится писать один и тот же код снова и снова. Кроме того, это позволяет нам добав­ лять в класс дополнительную функциональность, не изменяя его. ♦ Наследование носит транзитивный характер, а это означает, что если класс в на­ следуется от класса а, то все подклассы в автоматически также наследуются от класса а. В приведенном далее примере используется концепция наследования. In [9]: # Базовый или родительский класс Person class Person: def __ init__ (self, name): self.name = name # производный или дочерний класс Employee(Person) # функция super() используется для родительского класса class Employee(Person): def __ init__ (self, employee_id, name): super (). init__ (name) self.employee_id = employee_id In [10]: employee = Employee(52, "Peter") print(employee) |< main .Employee object at Ox000001E183BC09Q8> 11.6. Множественное наследование Когда дочерний класс наследуется от нескольких родительских классов, это назы­ вается множественным наследованием (рис. 11.7). Рис. 11.7. Множественное наследование
Классы | 237 При множественном наследовании функциональность всех базовых классов насле­ дуется в производном класс. Синтаксис множественного наследования аналогичен одиночному наследованию. Синтаксис множественного наследования Python: class Базовый_класс1: тело базового класса 1 class Базовый_класс2: тело базового класса 2 class Производный_класс(Базовый_класс1, Базовый_класс2) : тело производного класса Обратите внимание на разделенные запятой имена двух базовых классов в объяв­ лении производного класса. У него может быть любое количество родительских классов, от которых он наследует свою функциональность. В простейших случаях поиск атрибутов, унаследованных от родительского класса, выполняется как поиск в глубину слева направо, а не двойной поиск на одном уровне иерархии. Таким образом, если атрибут не найден в производном классе, он ищется в базовом классе 1, затем (рекурсивно) в родительских классах базового класса 1, и если он не был найден в этой ветке иерархии, то тогда поиск продолжа­ ется в базовом классе 2 и т. д. Пример кода с множественным наследованием: In [11]: class Basel: def __ init__ (self): self.strl = "Personl" print("Basel") class Base2: def __ init__ (self): self.str2 = "Person2" print("Base2") class Derived(Basel, Base2): def __ init__ (self) : Basel.__ init__ (self) # вызов конструктора Basel Base2.__ init__ (self) # и конструктора Base2 print("Derived") def printStrs(self): print(self.strl, self.str2) # создание экземпляра класса Derived person = Derived() # method printStrs() производного класса person выводит # строки из базовых классов "Personl" и "Person2" person.printStrs()
238 | Глава 11 Basel Base2 Derived Personl Person2 Наследование не ограничивается одним родителем и одним ребенком. Наследова­ ние может быть намного более сложным, многоуровневым и гибридным. На диа­ грамме на рис. 11.8 показаны все виды возможных отношений. Определить новый производный класс также довольно просто. Для этого нужно лишь записать имена всех классов, от которых он наследуется, в круглых скобках через запятую. Используйте приведенную диаграмму и запишите все определения классов само­ стоятельно. Такое простое упражнение поможет вам лучше понять эту концепцию. Рис. 11.8. Многоуровневое и гибридное наследование Пока мы лишь в теории рассуждали о том, как работает наследование. Теперь давайте напишем несколько простых программ, чтобы углубить теоретическое понимание на практике. Единственное отличие от приведенного ранее примера заключается в том, что мы будем использовать функцию super () для доступа к ме­ тодам базового класса. In [12]: # базовый класс class Person: def __ init__ (self, name, surname, year_of_birth): self.name = name self.surname = surname self.year_of_birth = year_of_birth def age(self, current_year): return current_year - self.year_of_birth def __ str__ (self) : return " (} {} was born in year {}.". format ( self.name, self.surname, self.year_of_birth) In [13]: nilabh = Person("Nilabh", "Nishchhal", 1998) print(petya) |Nilabh Nishchhal was born in year 1998.
Классы In [14]: | 239 # наследование class Student(Person): def __ init__ (self, student_id, name, surname, year_of_birth): super().__ init__ (name, surname, year_of_birth) self. student_id = student_id Siddharth = Student(l, 'Siddharth', 'Tiwari', 1985) print(Siddharth) |Siddharth Tiwari was born in year 1985. Объект siddharth ведет себя так же, как Person, но у него в числе прочего есть еще ID студента. Класс Person — базовый класс для student, а класс student — один из производных классов Person. Имейте в виду, что производный класс знает о своих базовых классах, а обратное неверно. Производный класс наследуется не только от своих базовых классов, но и от их базовых классов, образуя дерево наследования, которое начинается с самого базового объекта. Вы также можете заметить, что в подклассе student нет метода_ str__ , поэтому для строкового представления используется метод родительского класса, как показано выше. Что делать, если нам нужно определить новое строковое представление в дочернем классе student? 11.6.1 . Переопределение методов При наследовании можно добавлять в дочерний класс новые методы и атрибуты. А чтобы изменить поведение метода, определенного в родительском классе, можно переопределить этот метод в дочернем классе. Чтобы переопределить метод, доста­ точно просто определить его еще раз. Рассмотрим на примере: In [15]: class Student(Person): def __ init__ (self, student_id,name, surname, year_of_birth): super().__ init__ (name, surname, year_of_birth) self.student_id = student_id def __ str (self): return "{} {} (student id {}) was born in year {}."\ .format(self.name, self.surname, self. student_id, self. year_of__birth) siddharth = Student(1, 'Siddharth', 'Tiwari', 1985) print(siddharth) Isiddharth Tiwari (student id 1) was born in year 1985
240 Глава 11 | Обратите внимание на разницу в выходных данных в этом коде с наследованием. Мы переопределили строковое представление базового класса на новое, опреде­ ленное в дочернем классе. Существует интересный способ заглянуть в объект класса. С помощью функции help о вы можете узнать все подробности об объекте. Кроме того, эта же функция позволяет понять порядок разрешения методов. Для примера рассмотрим информа­ цию об объекте siddharth, который мы создали как экземпляр класса student. В выведенном сообщении будет написано, к какому классу объект принадлежит, а также его родительские классы. Порядок разрешения методов (method resolution order) начинается с дочернего класса, поднимается по иерархии вверх к родитель­ ским классам и заканчивается встроенными объектами. Вы также увидите методы, определенные для этого класса, и методы, унаследованные от родителей. Это важ­ ная функция для глубокого погружения в любой объект. In [16]: help(siddharth) main__ object: Help on Student in module class Student(Person) I Student(student_id, name, surname, year_of_birth) I I Method resolution order: I Student I Person | builtins.object I I Methods defined here: I | I __ init__ (self, student_id, name, surname, year_of_birth) Initialize self. See help (type(self)) for accurate signature. I I I __ str__ (self) Return str(self). Methods inherited from Person: age(self, current_year) Data descriptors inherited from Person: __ diet__ dictionary for instance variables (if defined) __ weakref__ list of weak references to the object (if defined)
Классы | 241 11.7. Полиморфизм Полиморфизм в общем означает наличие ярких или разных форм одного и того же. В мире программирования полиморфизм — это способность функции с одним и тем же именем выполнять разные операции для разных данных. Полиморфизм по­ зволяет создавать структуру, которая может работать с объектами разных типов1. Это позволяет функциям использовать объекты разных типов в разное время. В объектно-ориентированном программировании полиморфизм позволяет исполь­ зовать объект, относящийся к определенному классу, таким же образом, как если бы это был объект совершенно другого класса. В отличие от многих других популярных объектно-ориентированных языков про­ граммирования, таких как Java, Python не поддерживает полиморфизм во время компиляции или перегрузку методов. Если у класса или в скрипте Python есть не­ сколько методов с одинаковым именем, метод, определенный последним, переоп­ ределяет предыдущий. Поэтому полиморфизм методов в Python не поддерживается. 11.8. Абстракция и инкапсуляция Абстракция и инкапсуляция — две основные концепции ООП, наряду с наследова­ нием и полиморфизмом. Абстракция означает сокрытие сложности объекта и отображение только его ос­ новных характеристик. Другими словами, абстракция означает сокрытие реальной реализации, а «наружу» пользователю показывается только то, что ему нужно для использования. В качестве примера из реальной жизни можно привести любой объект, который мы используем, например смартфон. Пользуясь смартфоном, мы видим только интер­ фейс и не знаем, что происходит внутри. Мы не собираемся здесь углубляться в концепцию абстракции и рассматривать, как она реализована в Python. Если же вам интересно, вы можете изучить этот вопрос самостоятельно. Инкапсуляция является одной из фундаментальных концепций ООП. Инкапсуляци­ ей называют идею обертывания данных и работающих с ними методов в один мо­ дуль. Это накладывает ограничения на прямой доступ к переменным и методам и помогает предотвратить порчу данных. Чтобы избежать случайного изменения, к переменной объекта можно обращаться только в методах объекта. Такие пере­ менные называются приватными. При работе с классами предоставление глобального доступа ко всем переменным, используемым в программе, — не лучший выбор. Инкапсуляция дает нам возмож- 1 AskPython, 2020 (https://www.askpython.com/python/oops/polymorphism-in-python) [4].
242 | Гпава 11 ность открыть доступ только к необходимым переменным объекта, не предоставляя программе полного доступа ко всем данным объекта. Класс — это пример инкапсуляции, поскольку он объединяет все связанные с объ­ ектом данные и функции. Рассмотрим реальный пример инкапсуляции. В правительствах стран есть различ­ ные министерства и ведомства, отвечающие за финансы, оборону, внутренний порядок, международные связи и т. д. Министерство финансов занимается всеми финансовыми вопросами и ведет учет всех данных, связанных с финансами. Мини­ стерство обороны занимается всей деятельностью, связанной с обороной, и ведет учет всех операций, связанных с обороной. Возможна ситуация, когда чиновнику министерства финансов по какой-то причине понадобятся данные об оборонных закупках за конкретный месяц. В этом случае ему не разрешен прямой доступ ко всем данным оборонного ведомства. Сначала ему нужно будет связаться с сотруд­ ником министерства обороны, чтобы ему предоставили конкретные данные. Вот что такое инкапсуляция. Здесь данные министерства обороны и его сотрудники объединены в структуру под одним названием «Министерство обороны». Исполь­ зование инкапсуляции помогает скрыть данные. И данные любого министерства, обороны, финансов или иностранных дел, скрыты от любой другой структуры. В терминах языка Python мы можем описать эту ситуацию с помощью разных клас­ сов Finance и Defence, с разными данными, экземплярами и методами. 11.9. Как контролировать доступ Сейчас все внутри наших классов является общедоступным. Давайте разберемся, как ограничить доступ и обеспечить правильную инкапсуляцию в Python. 11.9.1. Приватные переменные Приватных переменных экземпляра, к которым можно получить доступ только внутри объекта, в Python не существует. Но существует соглашение между про­ граммистами, которому соответствует большая часть кода Python: имя с префиксом подчеркивания (например, _spam) должно рассматриваться как защищенная часть API (будь то функция, метод или данные). Это следует рассматривать как нюансы реализации, и такие компоненты могут быть изменены без какого-либо уведом­ ления1. Существуют 3 типа переменных: ♦ публичные; ♦ защищенные; ♦ приватные. Когда мы объявляем переменные в классе Python, они изначально являются обще­ доступными (публичными), например self .name = name. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Классы | 243 Чтобы сделать переменную защищенной, перед именем переменной ставится сим­ вол подчеркивания, например self . name = name. Доступ к защищенной переменной могут получить произвдные классы. Чтобы сделать переменную приватной (закрытой), перед именем переменной ста­ вят два символа подчеркивания, например seif._name = name. К приватной пере­ менной производные классы доступа не имеют. 11.10. Резюме В этой главе вы познакомились с объектно-ориентированным программированием и концепцией классов в Python. Это очень мощный инструмент, и пользоваться им вы будете очень часто. Вы видели, что в Python все является объектом. Мы узнали, как определять и инициализировать классы, создавать экземпляры классов. Увиде­ ли, как функции, определенные внутри класса, работают как методы объекта этого класса. Затем мы узнали очень важную концепцию наследования и множественного наследования в классе. Мы также коснулись понятий полиморфизма, абстракции и инкапсуляции. Наконец, мы узнали о приватных, защищенных и публичных пере­ менных. 11.11. Упражнения 11.11.1. Ответьте на вопросы 1. Что такое объектно-ориентированное программирование? В чем его преимуще­ ства по сравнению процедурным программированием? 2. Расскажите, чем отличаются объект и класс. 3. Какие типы объектов бывают внутри класса? Чем они отличаются? 4. Класс — это шаблон объекта. Что это значит? 5. Что делает метод _init_? 6. В чем разница между методом и функцией? 7. Что такое наследование? 8. Какое значение имеет функция super () ? 9. Что происходит, когда в родительском и дочернем классах объявляются функ­ ции с одним и тем же именем? 10. Как сделать любую переменную в Python приватной? 11.11.2. Правда или ложь 1. Класс представляет собой шаблон, определяющий объекты одного типа. 2. Ключевое слово 3. Для инициализации атрибутов экземпляров класса нужно определить метод init . class обозначает начало определения класса.
244 | Глава 11 4. Параметр self нужно передать в конструктор при создании экземпляра. 5. Параметр self ссылается на создаваемый объект. 6. Объект может содержать в себе другие объекты. 7. Атрибут класса имеет общее значение для всех экземпляров этого класса. 8. В родительском классе есть ссылка на список со всеми его дочерними классами. 9. По умолчанию при создании экзепляра класса вызывается метод_ init__. 10. Когда мы определяем переменные в классе Python, они по умолчанию являются приватными. 11.11.3. Практические задания 1. Рассмотрим следующее определение класса: class Yourclass marks =10 name = "ABC" def__ init__ (self, marks, name): self.marks = marks self.name = name def display(self): print marks print name Напишите команду для создания объекта класса Yourclass. 2. Напишите класс с именем Rectangle, состоящий из длины и ширины, и метода, который будет вычислять площадь прямоугольника. 3. Напишите класс, который имеет два метода get_string() и print string (). Метод get stringo принимает строку от пользователя, a print string выводит строку в верхнем регистре. 4. Напишите класс, который меняет порядок слов в строке. Строка "hello world" превращается в "world hello". 5. Напишите класс для преобразования целого числа в римские цифры. 6. Определите класс с именем shape (фигура) и его дочерний класс Square (квадрат). Класс square имеет метод инициализации, который принимает в качестве аргу­ мента сторону квадрата. Оба класса имеют метод вычисления площади, который может выводить площадь на экран. Площадь фигуры shape по умолчанию рав­ на 0. 7. Определите класс student с заданными характеристиками. Атрибуты экземпляра: • номер курса; имя.
Методы: — для ввода номера курса и имени; • getdata () • printdata () — для вывода номера курса и имени. 8. Определите класс Marks, производный от класса student. Переменная экземпляра: • Оценки по пяти предметам. Методы: • inputdata () — • outdata () — вызов getdata () и ввод 5 оценок; вызов printdata () и отображение 5 оценок. Реализуйте классы на Python. 9. Гостиница xyz предлагает проживание, питание. а) Создайте класс ды и т. д. Accomodation с номером комнаты, типом комнаты, ценой арен­ б) Создайте класс Meal, содержащий код обеда, название, цену и т. д. в) Создайте класс г) Класс Customer Customer, содержащий номер клиента, его имя, адрес и т. д. должен наследоваться ОТ Accomodation И Meal. 11.11.4. Изучите самостоятельно 1. Придумайте реальные жизненные ситуации, такие как школа, классы, ученики и другие подобные примеры, где можно применить концепцию классов. Создайте свои собственные классы. 2. Прочтите о происхождении объектно-ориентированного программирования.
12 Ошибки и обработка исключений 12.1. Ошибки и исключения Программа на Python останавливается сразу, как только обнаруживает ошибку. Существуют (как минимум) два различных типа ошибок: синтаксические ошибки и исключения1. 12.1.1. Синтаксические ошибки Синтаксические ошибки, также известные как ошибки синтаксического анализа, пожалуй, чаще всего будут расстраивать вас в процессе изучения Python (да и после изучения тоже). Давайте рассмотрим простой пример. Выведем на экран строку "Hello world". Вам должно быть интересно, что может пойти не так в таком простом коде. Тем не менее: In [1]: print(("Hello World") File "<ipython-input-l-aa26dc90f998>", line 1 print(("Hello World") A SyntaxError: unexpected EOF while parsing Здесь нужно на секунду остановиться и, не вдаваясь в подробности, обратить вни­ мание на то, что именно вызвало ошибку SyntaxError. Вы заметили, что при вызове функции в начале было две открывающиеся круглые скобки, а в конце— только одна закрывающая? Эта мелкая опечатки вызвала ошибку в простейшем коде. Рассмотрим другой пример. Сейчас вы, наверное, уже поняли, что такое синтакси­ ческая ошибка, но вот еще один вариант. In [2]: 1 while True print('Hello world') Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
248 Гпава 12 | File "<ipython-input-2-2b688bc740d7>", line 1 while True print('Hello world') A SyntaxError: invalid syntax Опять же, попробуйте сами найти синтаксическую ошибку в приведенном выше коде. Синтаксический анализатор выводит строку с ошибкой и с помощью маленькой стрелки Л указывает на первое проблемное место в строке. Ошибка возникла (или, по крайней мере, обнаружена) в символе перед стрелкой: в нашем случае перед функцией print(), поскольку перед ней отсутствует двоеточие (:). Также в тексте ошибки выводится имя файла и номер строки, поэтому вы знаете, где искать про­ блему в скрипте. 12.1.2. Исключения1 Даже если оператор или выражение написаны синтаксически верно, они могут вы­ звать ошибку при попытке их выполнить. Ошибки, обнаруженные во время выпол­ нения, называются исключениями. Большинство исключений не являются фатальными. Вскоре вы и сами научитесь обрабатывать их в программах на Python. Но если исключения не обрабатываются, то это приводит к появлению сообщений об ошибках, как показано далее. In [3]: # ZeroDivisionError - деление на ноль 10 * (3/0) ZeroDivisionError Traceback (most recent call last) < ipython-input-3-a08cece41bf0> in <module> 1 # ZeroDivisionError 2 --- > 3 10 * (3/0) ZeroDivisionError: division by zero In [4]: # NameError - имя переменной не найдено 4 + spam * 3 NameError Traceback (most recent call last) <ipython-input-4-c428111670b3> in <module> 1 # NameError 2 --- > 34+ spam * 3 NameError: name 'spam' is not defined 1 Python Software Foundation, 2020 (https://docs.python.org/3Ztutorial/introduction.html) [21].
Ошибки и обработка исключений | 249 # TypeError - объект неподходящего типа In [5]: '2' + 2 Traceback (most recent call last) TypeError <ipython-input-5-9b532ade2a0a> in <module> 1 # TypeError 2 --- > 3 '2' +2 TypeError: can only concatenate str (not "int") to str Вместо того, чтобы показывать ошибку в общем виде, Python подробно рассказы­ вает, какой тип исключения был обнаружен. В последней строке сообщений об ошибке поясняется, что произошло. Исключения бывают разных типов, и тип исключения выводится в сообщении об ошибке. В данных примерах ЭТО ZeroDivisionError, NameError И TypeError. Это имена встроенных исключений Python. В остальной части сообщения приведена подроб­ ная информация о типе исключения и его причинах. Непосредственно перед текстом ошибки выводится фрагмент кода, в котором про­ изошло исключение, в виде обратной трассировки стека. Как правило, это список последних вызываемых строк кода, и в нем не содержатся строки, полученные из стандартного ввода. 12.2. Вызов исключений 12.2.1. Оператор raise' В Python есть различные встроенные исключения, а также можно создавать пользо­ вательские исключения. Оператор raise позволяет программисту сгенерировать встроенное исключение или вызвать свое собственное. In [6] : х = 15 if х > 10: raise Exception("х should not exceed 10") Traceback (most recent call last) Exception <ipython-input-6-31007f376f82> in <module> 2 3 if x > 10: --- > 4 raise Exception("x should not exceed 10") Exception: x should not exceed 10 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
250 Гпава 12 | Посмотрим на еще один пример. In [7]: raise NameError('Hi There') Traceback (most recent call last) NameError <ipython-input-7-72cl83edb298> in <module> --- > 1 raise NameError('Hi There') NameError: Hi There Обратите внимание на то, что в приведенных выше примерах оператор raise наме­ ренно вызывает исключение, причем не любое, а с явно указанным текстом ошиб­ ки. Единственный аргумент оператора raise— вызываемое исключение. Этот аргумент должен быть либо экземпляром исключения, либо классом исключения (ПРОИЗВОДНЫМ ОТ Exception). 12.2.2. Исключение AssertionError Вместо того, чтобы ждать, пока программа сломается где-то при выполнении, мы можем заранее использовать утверждения. Мы словно «утверждаем» с помощью оператора assert, что здесь должно выполняться определенное условие. Если условие, которое мы указали, оказывается истинным, программа продолжает вы­ полнение. Если условие окажется ложным, программа сгенерирует исключение AssertionError. In [8]: х = "Python" # если условие возвращает True, то ничего не происходит assert х == "Python" In [9]: # если условие возвращает False, возникает ошибка AssertionError: assert х == "Julia" Traceback (most recent call last) AssertionError <ipython-input-9-28c8b221d28d> in <module> 1 #if condition returns False, AssertionError is raised: 2 --- > 3 assert x == "Julia" AssertionError: Оператор assert удобно использовать при отладке кода. Вы можете написать сообщение, которое выведется, если код вернет в следующем примере. In [10]: х = "Python" # если условие возвращает False, возникает ошибка AssertionError assert х == "Julia", "х should be 'Python'" False, как
Ошибки и обработка исключений | 251 Traceback (most recent call last) AssertionError <ipython-input-10-c4bdd07152aa> in <module> 3 #if condition returns False, AssertionError is raised: 4 --- > 5 assert x == "Julia", "x should be 'Python'" AssertionError: x should be 'Python' 12.3. Обработка исключений 12.3.1. Операторы try и except1 Конструкция try-except в Python используется для перехвата и обработки исключе­ ний (рис. 12.1). Python выполняет блок try как обычную часть программы. Код, следующий за оператором except, является ответом программы на любое исключе­ ние, которое могло возникуть в блоке try. Рис. 12.1. Конструкция try-except Как мы видели ранее, Python выдает исключение, если синтаксически правильный код генерирует ошибку. Если исключение не обработать, оно приведет к сбою про­ граммы. То, как ваша программа реагирует на исключения, определяется в блоке except. Следующий пример поможет вам разобраться в блоках try и In [12]: except: while True: try: x = int(input("Please enter a number: ")) break except ValueError: printfOops! That was no valid number. Try again...") Please enter a number: T Oops! That was no valid number. Try again... Please enter a number: 5 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
252 Гпава 12 | Конструкция try-except работает следующим образом: 1. Сначала выполняется блок try (инструкции между ключевыми словами try И except). 2. Если не возникает исключения, блок except пропускается и выполнение завер­ шается. 3. Если во время выполнения блока try возникает исключение, остальная часть блока пропускается. Затем, если тип возникшего исключения соответствует ука­ занному после ключевого слова except, выполняется блок except, а затем про­ должает выполняться следующий код за пределами блока. 4. Если возникает исключение, отличное от указанного в блоке except, оно переда­ ется во внешние операторы try. Если исключение так и не будет перехвачено, это означает, что программа встретила необработанное исключение и ее выпол­ нение останавливается с сообщением об ошибке. После оператора try может быть более одного блока except, в которых можно обра­ ботать разные исключения. В любом случае будет выполнено не более одного бло­ ка except. При этом обрабатывают только те исключения, которые возникли в соот­ ветствующем блоке try, но не в других блоках except того же оператора try. В блоке except можно указать несколько исключений в виде кортежа, например: except (RuntimeError, TypeError, NameError): Совет Обработка одного базового исключения Exception «скрывает» все ошибки, даже со­ вершенно неожиданные. Поэтому следует избегать обработки только базовых исклю­ чений в программах на Python. Вместо этого лучше перехватывать более конкретные типы исключений. 12.3.2. Блок else1 У конструкции try-except есть необязательный блок else, который может следовать после всех блоков except. В нем указывается код, который должен выполниться, если блок try не вызвал исключения (рис. 12.2). Другими словами, используя блок else, вы говорите программе выполнить опреде­ ленный код только в случае отсутствия исключений. Использование блока else лучше, чем добавление дополнительного кода в блок try, поскольку позволяет из­ бежать случайного перехвата исключения, которое возникло не в текущем блоке try-except. In [13]: import sys for arg in sys.argv[l:]: try: f = open(arg, 'r') 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Ошибки и обработка исключений | 253 except OSError: print('cannot open', arg) else: print(arg, 'has', len(f.readlines ()), 'lines') f.close() Рис. 12.2. Конструкция try-except-else Обработчики исключений перехватывают исключения не только в том случае, если они возникли в самом коде блока try, но и когда исключения возникают внутри функций, которые вызываются (даже косвенно) в блоке try. Например: In [14]: def this_fails(): х = 1/0 try: this_fails () except ZeroDivisionError as err: print('Handling run-time error:', err) |Handling run-time error: division by zero 12.4. Завершающий блок1 У оператора try есть еще один необязательный блок finally, предназначенный для выполнения какой-либо очистки, которую требуется выполнить в любом случае. Например: In [15]: try: raise Keyboardinterrupt finally: print('Goodbye, world 1') 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
254 | Глава 12 Goodbye, world! Keyboardinterrupt Traceback (most recent call last) <ipython-input-15-7786db0b9fdl> in <module> 1 try: raise Keyboardinterrupt ----- > 2 3 finally: 4 print('Goodbye, world!') Keyboardinterrupt: Обратите внимание, что, несмотря на исключение, последний оператор (в блоке finally) был выполнен. Если блок finally добавлен, он выполнится напоследок перед выходом из всей кон­ струкции try (рис. 12.3). Блок finally запускается всегда, независимо от того, воз­ никло ли исключении в блоке try или нет. Рис. 12.3. Конструкция try-except-else-finally Приведем несколько более сложных случаев. ♦ Если во время выполнения блока try возникает исключение, оно может быть обработано с помощью блока except. Если исключение не обрабатывается бло­ ком except, исключение повторно вызывается после выполнения блока finally. ♦ Исключение могло произойти во время выполнения блока except или else. В этом случае, опять же, исключение повторно возникает после выполнения блока finally. ♦ Если в блоке try встретился оператора break, continue или return, блок finally будет выполнен непосредственно перед выполнением оператора break, continue ИЛИ return. ♦ Если блок finally содержит оператор return, то вернется значение из оператора return блока finally, а не значение из оператора return блока try.
Ошибки и обработка исключений | 255 12.5. Резюме В этой главе мы поговорили о разнице между синтаксическими ошибками и исключениями, вы также рассмотрели способы создания, перехвата и обработки исключений в Python. Мы рассмотрели следующие операторы. ♦ Оператор raise позволяет в любой момент вызвать исключение. ♦ Оператор assert позволяет проверить, выполняется ли определенное условие. Если условие не выполняется, генерируется исключение. ♦ Весь код в блоке try последовательно выполняется, пока программа не обнару­ жит исключение. ♦ Если в блоке try возникнет исключение, оно будет обработано в соответствую­ щем блоке except. ♦ Блок else позволяет писать код, который будет выполнен только в том случае, если в блоке try не было никаких исключений. ♦ Блок finally содержит код, который должен выполняться всегда, независимо от того, возникло ли исключение. 12.6. Упражнения 12.6.1. Ответьте на вопросы 1. Когда возникает ошибка TypeError? 2. Опишите синтаксис оператора raise. 3. Какие бывают исключения? Как они обрабатываются в Python? 4. Зачем нужен блок finally? 5. Когда и зачем использовать оператор 6. Напишите синтаксис операторов try raise? и except. 7. Когда можно использовать оператор else при обработке исключений? 12.6.2. Правда или ложь 1. Программа Python завершается при обнаружении ошибки. 2. Ошибка SyntaxError возникает, когда мы делаем в коде орфографические ошибки. 3. При правильном синтаксисе кода никаких других ошибок возникнуть не может. 4. Оператор raise вызывает указанное исключение. 5. Блок try перехватывает исключение. 6. Блок except тоже используется для перехвата исключений. 7. В блоке try может быть более одного блока except.
256 | Глава 12 8. Перехват исключений не связан с рисками. 9. Блок else обязательно следует за блоком try. 10. Блок finally выполняется независимо от того, возникло ли в блоке try исклю­ чение. 12.6.3. Практические задания 1. Напишите функцию с именем oops(), которая явно вызывает исключение indexError при вызове. Затем напишите другую функцию, которая вызывает oops () внутри конструкции try-except и перехватывает ошибку. Что произойдет, если в функции oops () вместо IndexError будет вызываться KeyError? 2. Напишите функцию нахождения среднего значения списка чисел. Ваша функция должна иметь возможность обрабатывать пустой список, а также список, содер­ жащий строку. 3. Напишите программу, принимающую дату от пользователя в виде дня, месяца и года и вызывающую соответствующие ошибки, если передано недопустимое значение. Выводите сообщения об ошибке, пока пользователь не введет пра­ вильные значения. 4. Создайте класс Person для хранения личной информации (по вашему выбору) о человеке. Убедитесь, что ввод некорректных данных обрабатывается должным образом.
13 Модули и пакеты 13.1. Модули' Если вы выйдете из интерпретатора Python и затем откроете его снова, все напи­ санные вами ранее определения (функции и переменные) будут потеряны. Следо­ вательно, если вы хотите написать более длинную программу, вам лучше использо­ вать текстовый редактор (например, Блокнот (Notepad) или любое другое про­ граммное обеспечение), в нем подготовить код для интерпретатора и запускать этот файл. Это называется написать скрипт. По мере того как ваша программа будет расти, вы захотите разделить ее на не­ сколько файлов для облегчения дальнейшей работы. Кроме того, можно использовать написанную ранее функцию в нескольких своих программах, не копируя ее определение каждый раз. Для обеспечения такой функциональности в Python можно поместить определения в отдельный файл и использовать их в скриптах или в интерактивном режиме интерпретатора. Такой файл называется модулем. Определения из модуля можно импортировать в другие модули или в основной модуль. 13.1.1. Определение модуля Модуль— это файл, содержащий определения и инструкции Python. Имя такого файла состоит из имени модуля и расширения ру. В программировании модулем называется часть программного обеспечения с опре­ деленной функциональностью. Например, при создании видеоигры один модуль будет отвечать за логику игры, а другой — за отрисовку игры на экране. Каждый модуль — это отдельный файл, который можно редактировать независимо. Внутри самого модуля его имя (в виде строки) доступно как значение глобальной переменной __ name__ . Например, откройте свой любимый текстовый редактор (я использую стандартный Блокнот) и создайте в текущем каталоге файл с именем fibo.py с приведенным далее кодом. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
258 Гпава 13 | Совет При редактировании в программе Блокнот, чтобы сохранить файл с расширением ру, в окне сохранения выбирайте опцию Все файлы (All files) вместо текстового докумен­ та. Используйте кодировку ANSI. In [1]: # Модуль чисел Фибоначчи def fib(n): # вывести на экран ряд Фибоначчи до п а, b = 0, 1 while а < п: print(a, end=' ') a, b = b, а + b print() def fib2(n): # вернуть ряд Фибоначчи до п result = [] а, Ь = 0, 1 while а < п: result.append(а) a, b = b, а + b return result Теперь давайте разберемся, что мы только что сделали. Мы создали модуль под названием fibo. В этом модуле fibo есть две пользователь­ ские функции. По сути, мы могли бы просто определить в интерпретаторе функции f ib () и f ib2 (). Но, как я сказал ранее, они бы исчезли при закрытии интерпретатора. А что если мы хотим использовать эти функции регулярно? Для этого мы создаем скрипт, сохраняем его с подходящим именем, например fibo, и расширением ру, и наш новый модуль готов к работе. В Python существуют тыся­ чи встроенных модулей, и о некоторых мы скоро узнаем. Но умение создать мо­ дуль под свои собственные нужды тоже весьма кстати. Теперь, прежде чем мы вызовем наш новый модуль для решения задачи, давайте посмотрим, что делает функция fib () без вызова модуля. In [2]: fibo.fib(1000) Traceback (most recent call last) NameError Cipython-input-2-a6a8744949b5> in <module> --- > 1 fibo.fib (1000) NameError: name 'fibo' is not defined Как видите, встроенной функции созданный модуль. fib() не существует. Теперь вызовем только что Чтобы использовать наш модуль, нам нужно его импортировать. Зайдите в интер­ претатор Python и импортируйте этот модуль с помощью следующей команды: In [3]: import fibo
Модули и пакеты | 259 Эта команда не добавляет имена всех функций, определенных в модуле fibo, в те­ кущее пространство имен, а лишь добавляет туда имя модуля fibo. Используя имя модуля, вы можете получить доступ к его функциям. In [4]: fibo.fib(lOOO) |0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 In [5]: |Out[5J: fibo.fib2(100) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] In [6]: |Out[6]: fibo. name 'fibo' Если вы собираетесь использовать функцию часто, вы можете присвоить ей ло­ кальное имя: In [7]: fib = fibo.fib fib(500) |0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 13.1.2. Подробнее о модулях Кроме определений функций, модуль может содержать исполняемые инструкции. Эти инструкции предназначены для инициализации модуля. Они выполняются только один раз при импорте модуля с помощью оператора import. Определение функции тоже являются «инструкцией», которая при выполнении до­ бавляет имя функции в пространство имен модуля. У каждого модуля есть свое пространство имен, общее для всех его функций. Таким образом, вы можете использовать в модуле глобальные переменные, не бес­ покоясь о случайных конфликтах имен с глобальными переменными во всей про­ грамме'. 13.2. Импорт модулей2 13.2.1. Импорт модулей из других модулей Мы уже рассмотрели простой способ импорта любого модуля. Модули могут импортировать и другие модули, которые будут использоваться в его коде. Обычно, но не обязательно, все операторы import указываются в начале модуля (или скрипта). Имена импортированных модулей помещаются в простран­ ство имен импортирующего модуля. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21]. 2 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
260 | Гпава 13 13.2.2. Импорт имен из модуля напрямую Существует возможность импортировать отдельные функции из модуля непосред­ ственно в пространство имен импортирующего модуля. Например: In [8]: from fibo import fib In [9]: fib(500) [0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 Вы можете заметить разницу в способе вызова функции fib(). Раньше, когда им­ портировался целиком весь модуль, функция вызывалась как имя_модуля. функция о. Но здесь функция импортируется непосредственно в пространство импортирующе­ го модуля и используется самостоятельно. Но тут есть одна загвоздка. При таком импорте имя модуля в пространство имен не попадает (поэтому в этом примере модуль fibo не определен). И соответственно другие функции, которые не импортируются, оказываются не определены. Это становится ясно из следующего примера, где вызов функции fib2 () выдает сообщение об ошибке. In [10]: fib2(500) Traceback (most recent call last) NameError <ipython-input-l-a7b484686370> in <module> --- > 1 fib2 (500) NameError: name 'fib2' is not defined 13.2.3. Импорт всех имен из модуля Существует также способ импортировать все имена из модуля. In [11]: In [12]: |Out[12]: from fibo import * fib2(500) [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377] При этом импортируются все имена, кроме начинающихся с подчеркивания (_). В большинстве случаев программисты Python не используют эту возможность, по­ скольку она вводит в интерпретатор неизвестный набор имен, которые могут пере­ определить что-то из того, что вы уже определили ранее. Кроме того, это порожда­ ет плохо читаемый код. Однако импорт через символ (*) можно использовать для экономии времени в интерактивных сессиях. 13.2.4. Импорт модуля под другим именем Если при импорте за именем модуля следует ключевое слово as, то указанное после него имя становится новым именем модуля.
Модули и пакеты In [13]: | 261 import fibo as fibonacci # обычно этот способ используется для сокращения или # упрощения имени импортируемого модуля, # но я не стал использовать имя fib, чтобы не путать его с # одноименной функцией в этом модуле In [14]: fibonacci.fib(500) | 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 Этот оператор импортирует модуль так же, как и что теперь модуль называется fibonacci. Тот же способ можно использовать и со словом модуля: In [15]: import fibo, from с той лишь разницей, при импорте любого имени из from fibo import fib as fibonacci fibonacci(500) |0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 ~ Примечание Из соображений эффективности каждый модуль импортируется только один раз за сеанс интерпретатора. Следовательно, если вы изменили содержимое уже импорти­ рованного модуля, нужно перезапустить интерпретатор. Или, если вы хотите протес­ тировать в интерактивном режиме только один модуль, используйте importiib.reioadl), например: import importlib; importlib.reload(HMs_Moawi<r) 13.3. Стандартные модули' В Python есть встроенная библиотека стандартных модулей, описанная в отдельном документе Python Library Reference (далее «Справочник по стандартной библиоте­ ке»), Некоторые модули встроены в интерпретатор, и они предоставляют операции, которые не являются частью ядра языка, но тем не менее встроены по умолчанию для повышения эффективности или для доступа к основным средствам операцион­ ной системы, таким как системные вызовы. Этот набор модулей зависит от конфи­ гурации и от базовой платформы. Например, модуль winreg предоставляется только в системах Windows. Отдельного внимания заслуживает модуль sys, встроенный в любой интерпретатор Python. В переменных sys.psi и sys.ps2 содержатся строки, используемые как пер­ вичные и вторичные приглашения: »> import sys »> sys.psi '»> ’ 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
| 262 Глава 13 »> sys.ps2 I » »> sys.psl = 'C> ' C> print('Yuck!') Yuck! C> Здесь приведен пример запуска кода в командной строке, а не в Jupyter Notebook. Попробуйте выполнить то же самое в Jupyter Notebook. 13.4. Функция dir()' Встроенная функция dir () позволяет узнать, какие имена определены в указанном модуле. Функция возвращает отсортированный список строк. In [17]: import fibo, sys In [18]: dir(fibo) Out [18]: ['__ builtins__ ', '__ cached__ ', '__ doc__ ', '_file_', '__ loader__ ', '__name__ ', '__ package__ ', '__ spec__ ', 'fib', 'fib2'] In [19]: dir(sys) Out[19]: ['__ breakpointhook__ ', '__ displayhook__ ', # очень длинный список ... 'path_importer_cache', 'platform', 'prefix', 'psi', 'ps2', 'ps3', ... ] Запустите предыдущую инструкцию в своем Jupyter Notebook и посмотрите пол­ ный список. Обратите внимание, что в нем перечислены все типы имен: перемен­ ные, модули, функции и т. д. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html) [21].
Модули и пакеты | 263 Функция dir () не перечисляет имена встроенных функций и переменных. Если вам нужен их список, они определены во встроенном модуле builtins. 13.5. Пакеты Пакет представляет собой набор модулей. Суть пакетов легко понять по аналогии с тем, как мы храним данные на компьюте­ ре. Для разных типов файлов мы используем разные папки. Например, в одной папке хранятся музыкальные файлы, а в другой — фотографии. Внутри папок могут быть вложенные папки. Аналогично этому в Python используются пакеты вместо папок и модули вместо файлов. По мере того как наша программа (или проект) обрастает все большим количеством модулей, мы помещаем схожие по назначению модули в один пакет, а разные по назначению модули— в разные пакеты. Это позволяет сделать проект управляе­ мым и концептуально понятным. Как в папке могут быть вложенные папки и файлы, так и в пакетах могут быть под­ пакеты и модули. Папка должна содержать файл с именем __ init__ .ру, чтобы Python обрабатывал ее как пакет. Этот файл содержит код инициализации пакета. Пакеты позволяют структурировать множество пакетов и модулей, помогают до­ биться хорошо организованной иерархии и облегчают доступ к папкам и модулям. Пакеты — это способ структурировать пространство имен модулей Python с помощью точечной нотации. Например, имя модуля а.в обозначает подмодуль с именем в в пакете а. Так же как использование модулей избавляет авторов модулей от необ­ ходимости думать об именах глобальных переменных, использование разделенных точками имен модулей спасает авторов многомодульных пакетов, таких как NumPy или Pillow, от необходимости заботиться о конфликтах имен модулей1. 13.5.1. Пример пакета sound2 Предположим, вы хотите разработать набор модулей (пакет) для обработки звуко­ вых файлов и звуковых данных. Существует множество различных форматов зву­ ковых файлов (обычно они отличаются по расширению, например: wav, aiff, au, mp3 и т. д.). Таким образом, вам придется создать и поддерживать большую кол­ лекцию модулей для работы с различными форматами файлов. Кроме того, сущест­ вует множество различных операций, которые можно выполнять со звуковыми данными (например, микширование, добавление эха, применение эквалайзера, соз­ дание искусственного стереоэффекта), поэтому вам придется писать огромное количество модулей для выполнения этих операций. Структура вашего пакета (выраженная в терминах иерархической файловой системы) может выглядеть так, как продемонстрировано на рис. 13.1. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21]. 2 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.html ) [21].
264 | Гпава 13 Рис. 13.1. Пакет sound, вложенные пакеты и файлы На этом рисунке показано лишь упрощенное представление о том, как пакет, под­ пакет и модули связаны друг с другом. Видно, что подпакеты находятся внутри блока кода пакета, а модули находятся внутри соответствующих подпакетов. __init__.py formats/ __ init__ .ру waveread.ру wavewrite.ру aiffread.ру aiffwrite.ру auread.py auwrite.py effects/ пакет верхнего уровня инициализация пакета sound подпакет для работы с разными форматами подпакет звуковых эффектов _init_.py echo.py surround.py reverse.py подпакет для фильтров filters/ __ init__ .py equalizer.py vocoder.py karaoke.py
Модули и пакеты | 265 Файлы__ init__ .ру позволяют Python обрабатывать папки с файлами как пакеты. Это предотвращает непреднамеренное перезаписывание модулей с одинаковыми именами, например string. В простейшем случае файл__ init__ .ру может быть пус­ тым файлом, но в нем может выполняться код инициализации пакета или устанав­ ливаться переменная_ all__ . 13.5.2. Вызов пакета для дальнейшего использования1 Чтобы использовать пакет, сначала его нужно импортировать. Пользователь может импортировать из пакета отдельные модули. Например, вот так можно импортиро­ вать модуль echo подпакета effects, который находится внутри пакета sound: import sound.effects.echo Эта команда загружает модуль sound.effects.echo. Теперь, если мы хотим использо­ вать функцию echofilter о из этого модуля, нам нужно вызвать ее, указав ее полное имя с именами пакетов и модуля: sound.effects.echo.echofilter(input, output, delay=0.7, atten=4) Это выглядит громоздко и длинно, и такой код в большой программе может стать источником ошибок. К счастью, существует альтернативный способ импорта под­ модуля: from sound.effects import echo Такой импорт тоже загружает подмодуль echo и делает его доступным без префикса пакета, поэтому его можно использовать следующим образом: echo.echofilter(input, output, delay=0.7, atten=4) Есть также возможность прямого импорта нужной функции или переменной: from sound.effects.echo import echofilter Опять же, мы загружаем подмодуль вится доступна напрямую: echo, но функция echofilter () при этом стано­ echofilter(input, output, delay=0.7, atten=4) Обратите внимание, что при использовании конструкции from пакет import элемент импортировать можно либо модуль (или подпакет), либо другой объект, опреде­ ленный в пакете, например функцию, класс или переменную. Оператор импорта сначала проверяет, определен ли элемент в пакете; в противном случае он предпо­ лагает, что это модуль, и пытается его загрузить. Если его не удается найти, возни­ кает исключение ImportError. А в конструкции типа import элемент.подэлемент,подподэлемент каждый элемент, кро­ ме последнего, должен быть пакетом; последний элемент может быть модулем или пакетом, но не может быть классом, функцией или переменной, определенной в предыдущем элементе. 1 Python Software Foundation, 2020 (https://docs.python.Org/3/tutorial/introduction.htnil ) [21].
266 | Гпава 13 13.5.3. Популярные пакеты в Python Python— один из самых популярных языков, используемых специалистами по данным и разработчиками программного обеспечения для анализа данных. Одна из сильных сторон Python заключается во множестве доступных пакетов, написанных программистами со всего мира. С данными можно работать и в обычном Python, но существует довольно много библиотек с открытым исходным кодом, которые значительно упрощают такую работу. Как мы видели, пакеты нужны для управления аналогичными по своей функции модулями и файлами, которые выполняют определенные виды задач. В этой книге мы познакомимся с некоторыми пакетами, предназначенными для трех основных областей Data Science: ♦ сбор данных; ♦ обработка данных и моделирование; ♦ визуализация данных. 13.5.3.1. Сбор данных Scrapy Это одна из самых популярных библиотек Python для работы с данными, помогает создавать программы сканирования (ботов) для извлечения из Интернета структу­ рированных данных, например URL-адреса или контактную информацию. Это от­ личный инструмент для сбора данных, который используется, например, в моделях машинного обучения Python. Разработчики используют эту библиотеку для сбора данных из API. Этот фрейм­ ворк написан по принципу Don't Repeat Yourself (DRY, «не повторяйся»). Такой инструмент вдохновляет пользователей на написание универсального кода, ко­ торый можно повторно использовать для создания и масштабирования больших поисковых роботов. 13.5.3.2. Обработка данных и моделирование NumPy NumPy (Numerical Python)— идеальный инструмент для научных вычислений и выполнения простых и более сложных операций над массивами. В этой библиотеке вы найдете множество удобных функций, выполняющих опера­ ции с «-мерными массивами и матрицами в Python. Библиотека помогает обрабаты­ вать массивы, в которых хранятся значения одного типа, и упрощает выполнение математических операций над массивами (и их векторизацию). Фактически векто­ ризация математических операций над массивом типа NumPy увеличивает произ­ водительность и ускоряет время выполнения.
Модули и пакеты | 267 SciPy Эта полезная библиотека содержит модули для выполнения вычислений из линей­ ной алгебры, интегрирования, оптимизации и статистики. Ее основная функцио­ нальность была построена на NumPy, поэтому вычисления с массивами она тоже поддерживает. SciPy отлично подходит для всех видов проектов научного про­ граммирования (в сфере естествознания, математики и инженерии). В библиотеке есть эффективные численные процедуры, такие как численная оптимизация, интег­ рирование и другие функции. Большое количество подробной документации упро­ щает работу с библиотекой. Pandas Эта библиотека создана с целью помочь разработчикам в обработке «маркирован­ ных» и «реляционных» данных. Работа библиотеки опирается на две основные структуры данных: Series (одномерный список элементов) и DataFrame (двумерная структура вроде таблицы с несколькими столбцами). Pandas позволяет преобразо­ вывать структуры данных в объекты DataFrame, обрабатывать отсутствующие дан­ ные, добавлять/удалять столбцы из DataFrame, вводить отсутствующие файлы и строить графики и гистограммы. Библиотека применяется для обработки и визуа­ лизации данных. Scikit-learn Это отраслевой стандарт для проектов Data Science, написанных на Python. Scikitlearn — это группа пакетов в SciPy Stack, которые были созданы для конкретных задач, например, для обработки изображений. В Scikit-learn для выполнения мате­ матических операций используется библиотека SciPy, предоставляющая удобный интерфейс для наиболее распространенных алгоритмов машинного обучения. Специалисты по данным используют эту библиотеку для выполнения стандартных задач машинного обучения и интеллектуального анализа данных, таких как класте­ ризация, регрессия, выбор модели, уменьшение размерности и классификация. А еще библиотека поставляется с качественной документацией и обладает высокой производительностью. TensorFlow TensorFlow — это популярный фреймворк Python для машинного обучения и глу­ бокого обучения, разработанный в Google Brain. Это лучший инструмент для таких задач, как идентификация объектов, распознавание речи и многих других задач. Он помогает в работе с искусственными нейронными сетями, которым необходимо обрабатывать несколько наборов данных. Библиотека включает в себя различные помощники по слоям (tflearn, tf-slim, skflow), которые делают ее еще более функ­ циональной. В TensorFlow постоянно появляются новые версии, включая исправ­ ления потенциальных уязвимостей безопасности или улучшения интеграции TensorFlow и GPU.
268 | Гпава 13 13.5.3.3. Визуализация данных Matplotlib Это стандартная библиотека Data Science, которая позволяет визуализировать дан­ ные, такие как двумерные диаграммы и графики (гистограммы, диаграммы рассея­ ния и графики в недекартовых координатах). Matplotlib — одна из тех библиотек построения графиков, которые полезны в проектах по Data Science благодаря объектно-ориентированному API для встраивания графиков в приложения. Благодаря этой библиотеке Python может конкурировать с такими научными инст­ рументами, как MATLAB или Mathematica. Однако при использовании этой биб­ лиотеки для создания сложных визуализаций разработчикам приходится писать больше кода, чем обычно. Обратите внимание, что популярные библиотеки по­ строения графиков без проблем работают с Matplotlib. Seaborn Библиотека Seaborn создана на основе Matplotlib и служит полезным инструментом машинного обучения Python для визуализации статистических моделей — тепло­ вых карт и других типов визуализаций, в которых приводится сводка данных и отображаются общие распределения. При использовании этой библиотеки вам доступна широкая галерея визуализаций (включая сложные средства, такие как временные ряды, совместные графики и скрипичные диаграммы). Bokeh Эта библиотека — отличный инструмент для создания интерактивных и масштаби­ руемых визуализаций внутри браузеров с помощью виджетов JavaScript. Библиоте­ ка полностью независима от Matplotlib. Она ориентирована на интерактивность и представляет визуализации в современных браузерах аналогично D3.js (Data-Driven Documents). В Boken есть различные типы графиков, возможности взаимодействия (например, связывание графиков или добавление виджетов JavaScript) и стили. Plotly Этот веб-инструмент для визуализации данных, в котором уже встроено немало полезной графики, — подробнее вы можете узнать на сайте plotly.com. Библиотека очень хорошо работает в интерактивных веб-приложениях. Ее создатели активно расширяют библиотеку новой графикой и функциями для поддержки нескольких связанных представлений, анимации и интеграции перекрестной интеграции. * * * В следующих главах мы поработаем с некоторыми из этих пакетов для решения различных задач анализа данных, и вы познакомитесь с ними поближе. В конце концов, «каменщик должен хорошо знать свои инструменты», как и специалист по данным.
Модули и пакеты | 269 13.6. Резюме В этой главе мы узнали об организации проекта Python и о многократном исполь­ зовании своего кода. В конце концов, что толку писать программы, если их нельзя использовать снова? Модули — это инструмент Python для хранения кода в виде файлов, и модули можно вызывать в любой момент, когда они нам нужны. Пакеты позволяют организовать эти файлы или модули. Они берут на себя задачу иденти­ фикации и поиска нужного модуля и представляют собой репозиторий других под­ пакетов и модулей. Python — это язык с открытым исходным кодом, над которым работает много лю­ дей, внося свой вклад в его улучшение. Их усилия привели к созданию сотен опуб­ ликованных и общедоступных пакетов для Python, что делает язык универсальным. Мы рассмотрели несколько таких пакетов, но, поверьте, это даже не верхушка айс­ берга. По мере изучения и работы с ними вы будете постоянно сталкиваться со множеством других библиотек, предназначенных для той или иной задачи, кото­ рую вы выполняете. 13.7. Упражнения 13.7.1. Ответьте на вопросы 1. Что имеется в виду под «созданием скрипта»? Чем это полезно для програм­ миста? 2. Что имеется в виду под модулем Python? В чем важность модулей? 3. Как написать свой собственный модуль? 4. Как использовать созданный ранее модуль в своем нынешнем проекте? 5. Что такое пакет? Как он связан с модулем? 6. Как Python узнает, что нужно рассматривать какую-либо папку как пакет Python? Верно ли это и для подпакетов? 7. Какими способами можно импортировать модуль, находящийся внутри пакета? 8. Зачем создавать пакеты? Чем они полезны? 9. Какой вклад вносят общедоступные пакеты в язык вроде Python? Чем они по­ лезны для нового программиста или пользователя? 10. Назовите 5 общедоступных пакетов. 13.7.2. Правда или ложь 1. Если функции и переменные были определены хотя бы один раз, то они будут доступны вам всегда, даже если вы вышли из интерпретатора. 2. Текстовый редактор ничем не отличается от любого текстового редактора, тако­ го как MS Word.
270 | Глава 13 3. Определения из модуля можно импортировать в другие модули. 4. Имя файла модуля имеет расширение ру. 5. В Python нет встроенных модулей. 6. При импорте модуля с использованием синтаксиса from модуль import тируются все имена, кроме тех, которые начинаются с символа _. 7. * импор­ dir о — встроенная функция, позволяющая узнать, какие имена определены в модуле. 8. Пакет может содержать один или несколько модулей. 9. NumPy — популярный пакет интеллектуального анализа данных в Python. 10. Самая популярная библиотека визуализации в Python — это Matplotlib. 13.7.3. Изучите самостоятельно 1. Найдите в Сети документацию об общедоступных пакетах Python, приведенных в этой главе. Некоторые из них мы изучим в последующих главах, другие вы можете изучить самостоятельно. 2. Изучите другие пакеты, такие как Pillow для обработки изображений и Tkinter (ТК.) для разработки графических интерфейсов. 3. Узнайте, какие пакеты лучше всего подходят для парсинга веб-страниц в Python.
14 ПРОЕКТ 3: Конвертер валют с графическим интерфейсом В этом проекте мы создадим свой собственный конвертер валют. Величины меж­ дународных валют меняются в зависимости от их обменных курсов. Мы возьмем данные об обменном курсе с помощью APL Данные о курсах валют можно найти на сайте https://fixer.io. Прежде чем присту­ пить к программированию, вам нужно зайти на этот сайт и создать там бесплатную учетную запись, чтобы получите свой собственный код доступа к API. GUI (graphical user interface) — это графический пользовательский интерфейс. Это интерфейс приложений, с которым пользователь может работать с помощью мыши или клавиатуры и на котором реализовано большинство программ и приложений, используемых сегодня. В Python есть встроенная библиотека для создания приложений на основе графиче­ ского интерфейса под названием Tkinter. Эта библиотека проста в изучении и ис­ пользовании. В этой главе мы познакомимся с Tkinter и изучим ее основы. Но это ни в коем случае не учебник по Tkinter. Этот проект призван показать вам широту возможностей Python, помочь освоить теоретический материал, который мы уже рассмотрели в предыдущих главах, и превратить новые знания в практические на­ выки. Поскольку на выходе у нас будет большой фрагмент кода, который будет записан одним блоком, сперва нужно понять, что мы вообще собираемся делать. Затем я напишу полный код программы, и к тому времени вы сможете сами разобраться, что происходит в коде. Здесь наша цель — понять и применить на практике концепции, которые мы уже изучили в этой книге. В конце концов, ваши старания воплотятся в жизнь. Прежде чем мы начнем наше путешествие, позвольте мне показать вам, каким будет конечный результат (рис. 14.1). 14.1. Введение в Tkinter Tkinter является одной из многих библиотек для создания графических интерфей­ сов, но лишь она встроена в стандартную библиотеку Python. Это означает, что Tkinter входит в стандартную комплектацию Python и устанавливать ее отдельно не
272 | Гпава 14 Рис. 14.1. Конечный вид приложения «Конвертер валют» нужно. Чтобы познакомиться с Tkinter, мы создадим маленькое приложение с гра­ фическим интерфейсом «Hello World!». Сначала давайте рассмотрим код, запустим его и посмотрим на результат, а затем изучим основы Tkinter. In [1] : from tkinter import * root = Tk() root.title("Trial App") root.geometry("250x250") label_l = Label(root, text = "Hello World!") label_l.pack() root.mainloopO В конце выполнения код уходит в бесконечный цикл и открывает новое окно. Если вы не заметите окно сразу, посмотрите на панель задач на рабочем столе. Вы уви­ дите новое маленькое окошко, как на рис. 14.2. На рис. 14.2 стрелками отмечены 4 важных элемента: 1. Графический интерфейс, который мы только что создали с помощью приведен­ ного кода, отображается на панели задач в виде новой иконки. 2. Обратите внимание на символ * в нотации in[]. Он означает, что код выполняет­ ся в данный момент. В последней строке кода есть метод mainioop (). Он запуска­ ет бесконечной цикл до тех пор, пока открыто окно пользовательского интер­ фейса. Как только вы закроете это окно, символ * будет заменен на число, пока­ зывая, что код завершил работу. 3. Аналогично предыдущему пункту изменение иконки в заголовке Jupyter Notebook показывает, что веб-страница в данный момент находится в рабочем состоянии, т. к. окно графического интерфейса открыто и цикл выполняется. 4. Это окно графического интерфейса, которое мы создали. Оно не зависит от веб­ страницы. Вы можете перемещать его, сворачивать, разворачивать и закрывать. Давайте посмотрим на наш графический интерфейс (рис. 14.3). Сейчас этот интерфейс ничего не делает, а представляет собой лишь пустой холст. На нем вы можете разместить все, что угодно. Именно это сейчас мы и сделаем.
Проект 3: Конвертер валют с графическим интерфейсом | 273 Рис. 14.2. Запуск первого графического приложения из Jupyter Notebook f Trial Арр — □ X Hello World! Рис. 14.3. Первое пустое окно приложения 14.2. Основные шаги в Tkinter Tkinter очень проста в использовании и имеет модульную структуру, а значит, иде­ ально сочетается с подходом объектно-ориентированного программирования Python. Чтобы ее использовать, есть 6 очень простых шагов, которые можно повто­ рять любое количество раз (рис. 14.4): 1. Импорт библиотеки Tkinter (к настоящему моменту вы уже знаете, как импорти­ ровать модули в Python).
274 | Гпава 14 2. Создание объекта окна (имя переменной быть любым). 3. Изменение заголовка окна (это необязательно). 4. Создание виджета (есть много разных виджетов, мы рассмотрим некоторые из них). 5. Размещение виджета в окне (используя методы pack (), grid () или place ()) 6. Запуск бесконечного цикла с помощью метода mainioop (). Рис. 14.4. Шаги при написании кода в Tkinter Если вы не забываете следовать этому шаблону при работе с Tkinter, то остальное будет проще простого. Конечно, существует множество других опций и атрибутов, и некоторые из них мы рассмотрим в этой главе. Но основная канва соблюдается всегда, и к ней добавляется все остальное. 14.3. Окно интерфейса конвертера валют Давайте создадим окно интерфейса конвертера валют, который мы хотим сделать. Прямо сейчас мы создадим простое окно графического пользовательского интер­ фейса, которое не будет настоящим конвертером. Мы шаг за шагом рассмотрим сначала создание графического интерфейса, а затем код для создания конвертера. И наконец, мы объединим оба этих кода и создадим конвертер валют на основе графического интерфейса.
Проект 3: Конвертер валют с графическим интерфейсом | 275 14.3.1. Использование метода раск() Попробуйте набрать следующий код в Jupyter Notebook или в Spyder IDE. Запустив его, вы увидите приведенное на рис. 14.5 окно графического интерфейса. In [2]: from tkinter import * # создание главного окна в переменной root root = Tk() # изменение заголовка окна root.title("Currency Converter") # создание виджетов Label для текстовых меток label_l = Label (root, text = "Input the Amount for Conversion:", font = "arial 12 bold", borderwidth = 10) label_2 = Label(root, text = "Convert From Currency:", font = "arial 10", borderwidth = 10) label_3 = Label(root,text = "Convert to Currency:", font = "arial 10", borderwidth = 10) label_4 = Label(root,text = "Converted Amount:", font = "arial 10", borderwidth = 10) output = Labelfroot, text = "Print the output here:", font = "arial 10", borderwidth = 10) # создание виджетов Entry для полей ввода Enter_l = Entry(root, borderwidth = 5) Enter_2 = Entry(root, borderwidth = 5) Enter_3 = Entry(root, borderwidth = 5) # создание виджета Button для кнопки my_button = Button(root, text = "CONVERT", font = "arial 10", borderwidth = 5) # размещение виджетов в окне label_l.pack() label_2.pack() label_3.pack() label_4.pack() output.pack() Enter_l.pack() Enter_2.pack() Enter_3.pack() my_button.pack() # запускаем цикл, чтобы активировать графический интерфейс root.mainloopl)
276 | Гпава 14 Рис. 14.5. Добавление виджетов на окно с помощью метода раск() 14.3.2. Использование метода grid() Этот метод несколько сложный для понимания. Поля ввода должны находиться в том же ряду, что и их текстовые метки. Я намеренно подчеркнул здесь разницу между pack () И grid (). Метод pack о плотно упаковывает все виджеты в окне в порядке их появления. Но мы можем использовать метод grid О, чтобы разместить их на сетке по номерам строк и столбцов, а метод placet) позволяет разместить их в определенном месте в окне. Тем не менее place () используется не очень часто. Поэтому мы будем использовать тот же код, что и ранее, но с методом In [3]: from tkinter import * # создание главного окна в переменной root root = Tk() # изменение заголовка окна root.title("Currency Converter") # создание виджетов Label для текстовых меток label_l = Label(root, text = "Input the Amount for Conversion:", font = "arial 12 bold", borderwidth = 10) label_2 = Label(root, text = "Convert From Currency:", font = "arial 10", borderwidth = 10) label_3 = Label (root,text = "Convert to Currency:", font = "arial 10", borderwidth = 10) label_4 = Label (root,text = "Converted Amount:", font = "arial 12 bold", borderwidth = 10) # создание виджетов Entry для полей ввода Enter_l = Entry(root, borderwidth = 5) Enter_2 = Entry(root, borderwidth = 5) grid ().
Проект 3: Конвертер валют с графическим интерфейсом | 277 Enter_3 = Entry(root, borderwidth = 5) output = Entry(root, text = "Print the output here", font = "arial 10", borderwidth = 10) # создание виджета Button для кнопки my_button = Button(root, text = "CONVERT", font = "arial 10", borderwidth = 5) # размещение виджетов в окне label_l.grid(row = 0, column = 0) label_2.grid(row = 1, column = 0) label_3.grid(row = 2, column = 0) label_4.grid(row = 4, column = 0) Enter_l.grid(row = 0, column = 1) Enter_2.grid(row = 1, column = 1) Enter_3.grid(row = 2, column = 1) my_button.grid(row = 3, column = 0, columnspan = 2) output.grid(row = 4, column = 1) # запускаем цикл, чтобы активировать графический интерфейс root.mainloopf) Новое окно графического интерфейса выглядит так, как показано на рис. 14.6. За­ пустите код на своем компьютере и убедитесь в этом сами. □ f Currency Converter X Input the Amount for Conversion: Convert From Currency: Convert to Currency: convert! Рис. 14.6. Добавление виджетов на окно с помощью метода grid() 14.4. Код для конвертации валют Мы создали «внешнюю оболочку» или тело нашего конвертера валют. Теперь пора написать движок, который будет работать под капотом. Здесь вам следовало бы вспомнить концепцию классов, которую вы узнали в гла­ ве 11. В этом коде вы увидите практический пример создания класса и его исполь­ зования. Поскольку обменные курсы валют постоянно меняются, данные о них мы будем брать с сайта, на котором размещается информация о большинстве мировых валют, с помощью его API. Давайте воспользуемся сайтом https://fixer.io. Зайдите на этот
278 | Гпава 14 сайт и создайте на нем бесплатную учетную запись, чтобы получить свой собст­ венный код доступа к API. Для получения данных о курсах валют по API воспользуемся встроенным модулем requests. In [4]: import requests # создание класса конвертера валют class Currency_Converter: # словарь для хранения курсов валют rates = (} def__ init__ (self, url): # запрос данных с URL-адреса или веб-страницы data = requests.get(url).json() # извлечение курсов валют из полученных данных self.rates = data("rates"] # функция для выполнения конвертации def convert(self, from_currency, to_currency, amount): initial_amount = amount # т. к. базовой валютой является евро, то выполняем if from_currency != 'EUR': amount = amount I self.rates[from_currency] output = amount * self.rates[to_currency] # округление преобразования до 2 знаков после запятой output = round(amount * self.rates[to_currency], 2) # вывод в красивом формате для печати print('{} {} = {) {}'.format(initial_amount, from_currency, output, to_currency)) # точка входа в приложение if __name__ == " main__ ": # этот ключ у вас может не сработать, # зарегистрируйтесь и получите свой собственный ключ доступа ACCESS_KEY = "lcf94c2fd27ab40a0b510ccec2d0014b" url = str.__ add__ ( 'http://data.fixer.io/api/latest?access_key=', ACCESS_KEY) # вызов экземпляра класса converter = Currency_Converter(url) # получение данных от пользователя from_country = input("Convert From Currency: ") to_country = input("Convert to Currency: ") amount = int(input("Amount to be Converted: ")) converter.convert(from_country, to_country, amount)
Проект 3: Конвертер валют с графическим интерфейсом | 279 Convert From Currency: USD Convert to Currency: INR Amount to be Converted: 2 2 USD = 150.39 INR 14.5. Итоговое приложение Вы увидели, как создать внешнее тело приложения с помощью Tkinter, а также код, запускающий приложение и генерирующий фактический результат преобразо­ вания. Теперь мы объединим эти фрагменты. Но это будет не простая вставка одного фрагмента кода за другим. Примечание В предыдущем разделе я использовал пример класса только для того, чтобы вы по­ знакомились с концепциями классов в реальных действиях. То же самое можно сде­ лать напрямую, определив функцию, как вы увидите далее. In [5]: import tkinter as tk # создание окна конвертера валют # инициализация главного окна и присвоение переменной window window = tk.Tk() # изменение заголовка окна window.title("Currency Converter") # создание виджетов Label для текстовых меток Input_label = tk.Label(window, text = "Input the Amount for Conversion:", font = "arial 12 bold", borderwidth = 10) label_fc = tk.Label(window, text = "Convert From Currency:", font = "arial 12", borderwidth = 10) label_tc = tk.Label(window, text = "Convert to Currency:", font = "arial 12", borderwidth = 10) outputlabel = tk.Label(window, text = "Converted Amount:", font = "arial 12 bold", borderwidth = 10) # создание виджетов Entry для полей ввода input_amount = tk.Entry(window, font = "arial 12 bold", borderwidth = 5) from_currency = tk.Entry(window, font = "arial 12 bold", borderwidth = 5) to_currency = tk.Entry(window, font = "arial 12 bold", borderwidth = 5) output = tk.Entry(window, font = "arial 12 bold", borderwidth = 5)
280 | Гпава 14 # размещение виджетов в окне Input_label.grid(row = 0, column = 0) label_fc.grid(row = 1, column = 0) label_tc.grid(row = 2, column = 0) input_amount.grid(row = 0, column =1) from_currency.grid(row = 1, column = 1) to_currency.grid(row = 2, column = 1) outputlabel.grid(row = 4, column = 0) output.grid(row = 4, column = 1) # К этому моменту мы создали окно графического интерфейса, # теперь поработаем над кодом для конвертации. # Сначала мы получим данные о курсах валют с www.fixer.io # по ключу доступа, обязательно получите свой ключ доступа! ACCESS_KEY = "lcf94c2fd27ab40a0b510ccec2d0014b" url = str.__ add__ ('http://data.fixer.io/api/latest?access_key=', ACCESS_KEY) # импорт библиотеки запросов import requests # запрос данных с URL-адреса data = requests.get(url).json() # словарь с курсами валют из полученных данных rates = data["rates"] # функция, которая выполняет фактическое преобразование def currency_converter(from_currency, to_currency, input_amount): from_currency = from_currency.get() to_currency = to_currency.get() input_amount = float(input_amount.get()) if from_currency != "EUR": input_amount = input_amount / rates[from_currency] output.insert (0, round(input_amount * rates[to_currency], 2)) return convert_button = tk.Button(window, text = "CONVERT", font = "arial 16 bold", borderwidth = 10, padx = 50, bg = "powder blue", command = lambda: currency_converter(from_currency, to_currency, input_amount)) convert_button.grid(row = 3, columnspan = 2) window.mainloop() После запуска этого кода откроется окно приложения, показанное на рис. 14.7.
Проект 3: Конвертер валют с графическим интерфейсом | 281 Рис. 14.7. Окно приложения с пустыми полями ввода In [6]: # список валют, доступных для конвертации, здесь rates.keys О Out[6] 'AZN', 'BTC , 'COP', 'ЕТВ', 'GYD', ' ISK', 'KYD', 'MGA', 'NAD', 'PLN', 'SGD', 'TND', 'VND', 'ZMK', diet keys([ 'BAM', 'BBD', 'BTN', 'BWP', 'CRC, 'CUC', 'EUR', 'FJD', 'HKD', 'HNL', ' JEP', 'JMD', 'KZT', 'LAK', 'MKD', 'MMK', 'NGN', 'NIO', 'PYG', 'QAR', 'SHP', 'SLL', 'TOP', 'TRY', 'VUV', 'WST', 'ZMW', 'ZWL']) 'AED', BDT', BYN', CUP', FKP', HRK', JOD', LBP', MNT', NOK', RON', SOS', TTD', XAF', 'AFN', 'BGN', 'BYR', 'CVE', 'GBP', 'HTG', 'JPY', 'LKR', 'MOP', 'NPR', 'RSD', 'SRD', 'TWD', 'XAG', 'ALL', 'BHD', 'BZD', 'CZK', 'GEL', 'HUF', 'KES', 'LRD', 'MRO', 'NZD', 'RUB', 'STD', 'TZS', 'XAU', 'AMD', 'BIF', 'CAD', 'DJF', 'GGP', 'IDR', 'KGS', 'LSL', 'MUR', 'OMR', 'RWF', 'SVC, 'UAH', 'XCD', 'ANG', 'BMD', 'CDF', 'DKK', 'GHS', 'ILS', 'KHR', 'LTL', 'MVR', 'PAB', 'SAR', 'SYP', 'UGX', 'XDR', 'AOA', 'BND', 'CHF', 'DOP', 'GIP', 'IMP', 'KMF', 'LVL', 'MWK', 'PEN', 'SBD', 'SZL', 'USD', 'XOF', 'ARS', 'BOB', 'CLF', 'DZD', 'GMD', 'INR', 'KPW, 'LYD', 'MXN', 'PGK', 'SCR', 'THB', 'UYU', 'XPF', 'AUD', 'BRL', 'CLP', 'EGP', 'GNF', 'IQD', 'KRW', 'MAD', 'MYR', 'PHP', 'SDG', 'TJS', 'UZS', 'YER', 'AWG', 'BSD', 'CNY', 'ERN', 'GTQ', 'IRR', 'KWD', 'MDL', 'MZN', 'PKR', 'SEK', 'TMT', 'VEF', 'ZAR', Давайте посмотрим, чему равны 15 австралийских долларов (AUD) в пересчете на индийские рупии (INR). Для этого в окне конвертера в первом поле введите 15. За­ тем укажите в следующих полях значения AUD и INR соответственно и нажмите кнопку CONVERT. Результат будет примерно таким, как показано на рис. 14.8. Примечание У вас итоговая сумма, естественно, будет другой, т. к. курсы валют меняются каждый день и будут приходить новые данные с сайта валют. Рис. 14.8. Конвертация 15 австралийских долларов в индийские рупии
282 | Гпава 14 14.6. Резюме В этом проекте мы стали свидетелями того, как наши теории воплощаются в реаль­ ный проект, который можно посмотреть и потрогать (ну, по крайней мере, с помо­ щью курсора мыши). В этом проекте мы познакомились с библиотекой Tkinter для создания графического интерфейса. Мы изучили основные строительные блоки любого процесса создания графического интерфейса в Python, которые помогут вам в будущем создавать программы с графическими интерфейсами. Вы можете изу­ чить эту тему более подробно сами, но основы, которые вы узнали здесь, вам при­ годятся. Затем мы опробовали работу с классами в действии и создали класс, опре­ делили в нем методы, назначили локальные переменные, а затем создали экземпляр класса. Для преобразования валют мы вызвали метод экземпляра класса. Наконец, мы узнали, как создавать приложения с графическим интерфейсом, который умеет использовать функции для выполнения реальных задач. 14.7. Изучите самостоятельно I. Добавьте в созданном приложении еще одну кнопку, которая очищает поля вво­ да и вывода. Вам нужно добавить еще одну кнопку CLEAR и написать функцию по аналогии с работой кнопки CONVERT. 2. Попытайтесь реализовать поля выбора валюты в виде выпадающих списков, ис­ пользуя только те валюты, которые получены по API. 3. Почитайте о библиотеке Tkinter и узнайте, что еще можно сделать с ее по­ мощью.
15 Библиотека NumPy Эта глава опирается на документацию по NumPy в целом и руководства из серии «NumPy: the absolute basics for beginners», опубликованные сообществом SciPy1. NumPy Изображения, иллюстрирующие работу массивов NumPy, взяты с упомянутой учебной страницы NumPy и любезно предоставлены автором Джеем Аламмаром (http://jalammar.github.io/). Это лишь одна из многих статей и руководств по NumPy, предназначенных для обучения программистов всех уровней, от начинающих до продвинутых и опытных программистов. Я настоятельно рекомендую вам посетить этот веб-сайт сообщест­ ва SciPy и продолжить обучение на нем. В этой главе я не буду приводить много детальной информации, а вместо этого познакомлю вас с удивительными возмож­ ностями NumPy и научных вычислений на Python, что стало возможным благодаря участникам и разработчикам сообщества SciPy. 15.1. Введение в NumPy NumPy (Numerical Python) — это библиотека Python с открытым исходным кодом, которая используется практически во всех областях науки и техники. Это универ­ сальный стандарт для работы с числовыми данными в Python, который лежит в ос­ нове научных экосистем Python и PyData. NumPy используют все, от начинающих программистов до опытных исследователей, занимающихся современными науч­ ными и промышленными исследованиями и разработками. NumPy API широко ис­ пользуется в Pandas, SciPy, Matplotlib, Scikit-leam, Scikit-image и в большинстве других пакетов Python, применяющихся в Data Science и в научных исследованиях. В отличие от универсального Python, в который встроено множество структур дан­ ных, в NumPy есть всего одна структура — многомерный массив и различные про­ изводные объекты, в том числе матрицы (вспоминаем школьную алгебру). В основе NumPy лежит тип данных ndarray, который представляет собой однород­ ный многомерный массив, а также методы для эффективной работы с ним. NumPy добавляет в Python мощные структуры данных, позволяющие выполнять эффек- 1 SciPy, 2020 (https://numpy.org/devdocs/user/absolute_beginners.html) (45).
284 | Гпава 15 тивные вычисления над массивами и матрицами, и предоставляет огромную биб­ лиотеку высокоуровневых математических функций, которые работают с этими структурами данных. 15.1.1. Установка NumPy Поскольку библиотека NumPy не входит в базовую сборку Python, ее необходимо установить отдельно. Хорошо то, что это библиотека с открытым исходным кодом, а значит, ее можно скачать бесплатно. Еще одна хорошая новость — она уже есть на нашем компьютере. Когда мы уста­ навливаем Python, используя пакет Anaconda, с ним сразу же устанавливаются наи­ более популярные библиотеки Python. A NumPy — это самый популярный пакет Python. Но на всякий случай я все равно расскажу вам, как установить ее отдельно. В Python есть два способа установки пакета или библиотеки — через менеджеры пакетов Conda или Pip. Если у вас уже есть Python на компьютере, вы можете установить NumPy из ко­ мандной строки с помощью команды: conda install numpy или pip install numpy 15.1.2. Импорт NumPy Каждый раз, когда вы хотите использовать сторонний пакет или библиотеку в сво­ ем коде, вам сначала нужно импортировать их. Чтобы начать использовать библиотеку NumPy и все ее функции, необходимо им­ портировать ее с помощью оператора import: import numpy as пр (Сократим имя numpy до пр, чтобы сэкономить время и сохранить стандартизирован­ ный код, чтобы любой, кто будет работать с вашим кодом, мог легко его понять). 15.1.3. Разница между списком Python и массивом NumPy В NumPy есть огромное количество быстрых и эффективных способов создания массивов и обработки их числовых данных. Python позволяет хранить в одном спи­ ске данные разных типов, но в массиве NumPy все элементы должны быть одного типа. Математические операции, которые выполняются над массивами, были бы очень неэффективными, если бы элементы в массивах не были однородными. Сравнение списков list и массивов ndarray показано в табл. 15.1.
Библиотека NumPy | 285 ТАБЛИЦА 15.1 Список Python (list) Массив NumPy (ndarray) Список Python может содержать элементы разных типов Массив NumPy по умолчанию является однородным, т. е. данные внутри массива должны иметь один и тот же тип данных Поэлементные операции над списками невозможны Операции выполняются поэлементно Список Python по умолчанию одномерный Массив NumPy многомерный. Само слово ndarray означает n-мерный массив Элементы списка не обязательно должны храниться в непрерывной области памяти Элементы массива хранятся в памяти непрерывно 15.1.4. Зачем нам NumPy? Массивы NumPy быстрее и компактнее, чем списки Python. Массив занимает меньше памяти и удобнее в использовании. NumPy использует намного меньше памяти для хранения данных и имеет механизм для явного задания типа данных, что позволяет еще больше оптимизировать код. NumPy работает быстрее, чем списки, потому что массивы NumPy занимают мень­ ше места в памяти по сравнению со списками и, следовательно, быстрее загружа­ ются. Давайте приведем графическое пояснение. Посмотрим, как число 5 выглядит на компьютерном языке, в виде списка Python и как массив NumPy. Эта картинка мно­ гое вам объяснит (рис. 15.1). Формат int32 Бинарное представление числа 5 00000000 00000000 00000000 00000101 Массив NumPy 5 — 00000101 Список Python РАЗМЕР КОЛИЧЕСТВО ССЫЛОК ТИП ОБЪЕКТА ЗНАЧЕНИЕ ОБЪЕКТА 00000000 00000000 00000000 00000101 000000010011110111111110 10111100 00011010 110111011010010011011000 11001010 10111110 01100001 01000100 11111100 00000000 11001100 01011111 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000101 Рис. 15.1. Представление числа 5 в двоичном формате, как список Python и как массив NumPy Как видите, объект list имеет 4 атрибута: размер, количество ссылок, тип объекта и значение объекта. Все это занимает 28 байт памяти. Тот же объект в форме массива NumPy занимает всего 4 байта памяти. Есть еще одно преимущество массива NumPy в том, что он хранится в памяти не­ прерывно. Это означает, что данные хранятся без пробелов между ними. А вот спи­ ски разрознены. Давайте рассмотрим рис. 15.2, чтобы лучше это понять.
286 | Гпава 15 Рис. 15.2. Хранение массивов NumPy и списков Python в памяти 15.2. Массив NumPy Массив — это центральная структура данных библиотеки NumPy. Массив пред­ ставляет собой таблицу значений, содержащую информацию о необработанных данных, о том, как найти элемент и как интерпретировать элемент. В массиве есть сетка элементов, которые можно индексировать разными способами. Все элементы имеют один тип, который сохраняется в атрибуте dtype. Как уже упоминалось, класс массива NumPy называется ndarray. Иногда его назы­ вают просто array. Обратите внимание, что класс numpy. array— это не то же самое, что класс array, array стандартной библиотеки Python, который обрабатывает только одномерные массивы и гораздо менее функционален. Один из способов инициализировать массив NumPy — выполнить преобразование из списка Python. Например: In [1]: import numpy as пр a = np.array([1, 2, 3, 4, 5, 6]) a |Out[l]: array([l, 2, 3, 4, 5, 6]) Или можно использовать вложенные списки для создания двумерных или много­ мерных данных: In [2]: b = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) b Out[2] : array] [[ 1, 2, 3, 4b [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) Получить доступ к элементам массива можно с помощью квадратных скобок. Пом­ ните, что индексация в NumPy начинается с 0. Это означает, что если вы хотите обратиться к первому элементу массива, нужно указывать индекс 0. In [3]: print(b[0]) | [1 2 3 4] 15.2.1. Размерность массива Иногда массивы называют ndarray, что является сокращением от англ. N-dimensional array («-мерный массив). Здесь имеется в виду, что это просто массив с лю-
Библиотека NumPy | 287 бым количеством измерений. Иногда также встречаются термины ID-массив (одномерный массив) и 2D-Maccue (двумерный массив). Класс NumPy ndarray используется для представления как матриц, так и векторов. Вектор представляет собой одномерный массив (вектор-строка или векторстолбец — это одно и то же). Матрица — это двумерный массив. Для трехмерных массивов или массивов более высокой размерности обычно ис­ пользуется термин тензор. 15.2.2. Другие атрибуты массива Массив обычно представляет собой контейнер фиксированного размера с элемен­ тами одного типа и размера. Размерность массива и количество элементов в масси­ ве определяются его формой. Форма массива— это кортеж неотрицательных целых чисел, которые определяют размеры по каждому измерению. В NumPy измерения называются осями. Это означает, что если у вас есть двумер­ ный массив, который выглядит так: [[0., 0., 0.], [1., 1., 1.]] В вашем массиве 2 оси. Первая ось имеет длину 2, а вторая ось — длину 3. Как и в других контейнерах Python, к содержимому массива можно обращаться и изменять его с помощью индексации или среза. В отличие от типичных объектовконтейнеров, разные массивы могут совместно использовать одни и те же данные, поэтому изменения, внесенные в один массив, могут быть видны и в другом мас­ сиве. 15.3. Создание массива Чтобы создать массив NumPy, вы можете использовать функцию пр. array о. Чтобы создать простой массив, достаточно просто передать ему список. In [4] : import numpy as пр a = np.array([1, 2, 3]) Вы можете представить свой массив так, как изображено на рис. 15.3. Функция Массив NumPy 1 пр.array![1,2,3]) 2 з Рис. 15.3. Одномерный массив NumPy
288 | Гпава 15 Имейте в виду, что эти схемы предназначены только для того, чтобы в самом про­ стом виде объяснить вам концепции и механизмы NumPy. На самом деле массивы и операции с массивами устроены намного сложнее! Есть несколько способов создания массивов. Вы можете создать массив из обычного списка или кортежа Python, используя функцию пр.аггауО. Тип результирующего массива будет определяться типом эле­ ментов в последовательностях. In [5]: а = пр.аггау([2, 3, 4]) а |put[5] : In [6]: array([2, 3, 4]) b = np.array([1.2, 3.5, 5.1]) b |0ut[6]: In [7]: [out[7]: In [8]: |Out[8]: array([1.2, 3.5, 5.1]) a.dtype dtype('int32') b.dtype dtype(1float64') Довольно распространенная ошибка заключается в вызове этой функции с несколь­ кими аргументами вместо передачи одной последовательности в качестве аргу­ мента. In [9]: а = np.arrayd, 2, 3, 4) # НЕПРАВИЛЬНО Traceback (most recent call last) ValueError <ipython-input-8-7681c71c58ae> in <module> --- > 1 a = np.arrayd, 2, 3, 4) # НЕПРАВИЛЬНО ValueError: only 2 non-keyword arguments accepted In [10]: a = np.arraydl, 2, 3, 4]) # ПРАВИЛЬНО a |0ut[10]: array([l, 2, 3, 4]) Функция np. array о преобразует последовательность последовательностей в дву­ мерный массив, а последовательность двумерных массивов — в трехмерный мас­ сив и т. д. In [11]: b = пр.аггау([(1.5, 2, 3), b Out[11]: array([[1.5, 2. , 3. ], [4. , 5. , 6. ]]) (4, 5, 6)])
Библиотека NumPy | 289 15.3.1. Массивы из нулей, единиц и случайных чисел Часто элементы массива изначально неизвестны, известен лишь его размер. Поэто­ му в NumPy есть несколько функций для создания массивов с опеределенным на­ чальным заполнителем. Это сводит к минимуму необходимость увеличения разме­ ра массива в процессе работы, что требует немало ресурсов. Функция zeros () создает массив, заполненный нулями, функция ones о создает мас­ сив, заполненный единицами. По умолчанию тип элементов таких массивов — float641. In [12]: np.zeros (2) Out[12]: array;[0., 0.]) In [13]: np.zeros ((3, 4)) Out[13]: array;[[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]) In [14]: np.ones(2) Out [14]: array([l., 1.]) In [15]: np.onesf(3, 2)) Out[15]: array([[l., 1.], [1., 1.], [1., 1.]]) Функция empty о создает массив, начальное содержимое которого является случай­ ным и зависит от состояния памяти. Причина использования массива случайных чисел вместо нулей — это скорость. Но после этого нужно заполнить каждый эле­ мент! In [16]: # создание пустого массива с 2 элементами np.empty((2, 3)) Out[16): array([[0.01652764, 0.81327024, 0.91275558],” [0.60663578, 0.72949656, 0.54362499]]) Часто бывают случаи, когда мы хотим, чтобы NumPy сам задал значения массива. В NumPy есть также класс random. Generator для генерации случайных чисел. Вам достаточно лишь передать количество элементов, которые вы хотите сгенерировать (рис. 15.4 и 15.5). In [17]: rng = np. random, defaulting (0) rng.random(3) |Out[17]: array! [0.63696169, 0.26978671, 0.04097352]) 1 SciPy, 2020 (https://numpy.org/devdocs/user/absolute_beginners.html) [45].
290 | Глава 15 In [18]: rng.random((3, 2)) Out[18]: array([[0.01652764, 0.81327024], [0.91275558, 0.60663578], [0.72949656, 0.54362499]]) 0.5967 np.ones(3) np.zeros(3) 0.0606 0.2223 Рис. 15.4. Одномерные массивы из нулей, единиц и случайных чисел Рис. 15.5. Двумерные массивы из нулей, единиц и случайных чисел 15.3.2. Массив из диапазона значений Для создания последовательностей чисел в NumPy есть функция np.arangef), ра­ ботающая аналогично встроенной функции ranged в Python, но возвращающая массив. In [21]: |Out[21]: np.arange(4) array([0, 1, 2, 3]) Можно также создавать массивы, содержащие диапазон равномерно распределен­ ных значений. Для этого нужно указать первое число, последнее число и размер шага. In [22]: # массив значений от 2 до 9 с шагом 2 np.arange(2, 9, 2) |Out[22]: array][2, 4, 6, 8]) Когда в aranged передают аргументы с плавающей точкой, обычно невозможно предсказать количество полученных элементов из-за конечной точности этого формата. Поэтому в таких случаях лучше использовать функцию linspace (), кото­ рая вместо шага принимает в качестве аргумента количество элементов. In [23]: |0ut[23]: пр.linspace(0, 2, 9) array([0. #9 чисел от 0 до 2 , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
Библиотека NumPy | 291 15.3.3. Указание типа данных массива Хотя тип данных по умолчанию— это числа с плавающей точкой (np.float64), вы можете явно указать, какой тип данных вам нужен, используя ключевое слово dtype. In [25]: х = np.ones(2, dtype=np.int64) x |put[25]: array([l, 1], dtype=int64) In [26]: np.ones((2, 3, 4), dtype=np.intl6 ) Out [26]: array([[[l, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]], dtype=int!6) 15.3.4. Вывод массивов' Когда вы выводите массив на экран, NumPy отображает его аналогично вложенным спискам по таким правилам: ♦ последняя ось печатается слева направо; ♦ предпоследняя печатается сверху вниз; ♦ остальные оси печатаются сверху вниз, причем каждый фрагмент отделяется от следующего пустой строкой. Одномерные массивы выводятся как строки, двумерные— как матрицы, а трех­ мерные — как списки матриц. In [27]: а = np.arange(6) # одномерный массив print(а) |[0 1 2 3 4 5] In [28]: b = np.arange(12).reshape (4, 3) # двумерный массив print(b) [[ o 1 2] [ 3 4 5] [ 6 7 8] [ 9 10 11]] In [29]: с = np.arange(24).reshape(2, 3, 4) # трехмерный массив print(с) 1 SciPy, 2020 (https://numpy.org/devdocs/user/absolute_beginners.html) [45].
292 Глава 15 | [[[ о 1 2 3] [ 4 5 6 7] [ 8 9 10 И]] [[12 13 14 15] [16 17 18 19] [20 21 22 23]]] 15.4. Сортировка, добавление и удаление элементов массива 15.4.1. Сортировка Сортировка элементов массива выполняется с помощью простой функции sort(). При вызове функции вы можете указать ось, тип и порядок сортировки. Если мы возьмем этот массив: In [30]: arr = np.array([2, 1, 5, 3, 7, 4, 6, 8]) то можно быстро отсортировать числа в порядке возрастания следующим образом: In [31]: |Out[31]: np.sort(arr) array([l, 2, 3, 4, 5, 6, 7, 8]) В дополнение к функции sort (), которая возвращает отсортированную копию мас­ сива, вы можете использовать функции: ♦ argsort (), выполняющую непрямую сортировку по указанной оси; ♦ lexsort () для обратной устойчивой сортировки по нескольким ключам; ♦ searchsorted (), которая ищет элементы в отсортированном массиве; ♦ partition о для частичной сортировки. 15.4.2. Сложение (конкатенация) Пусть у вас есть вот такие массивы: In [32]: а = пр.array([1, 2, 3, 4]) b = пр.аггау([5, 6, 7, 8]) Вы можете объединить их с помощью In [33]: |Out[33]: пр.concatenate((а, b)) array) [1, 2, 3, 4, 5, 6, 7, 8]) А вот такие массивы: In [34]: concatenate (). х = пр.array([[1, 2], у = пр.array([[5, 6]]) [3, 4]])
Библиотека NumPy | 293 можно объединить так: In [35]: np.concatenate((х, у), axis=0) Out[35]: array([[l, 2], [3, 4], [5, 6]]) 15.4.3. Удаление Чтобы удалить элементы из массива, просто используйте индексирование и укажи­ те элементы, которые вы хотите сохранить. 15.5. Форма и размер массива У массивов есть целый ряд важных атрибутов. ♦ ndarray .ndim — это количество осей или размерность массива. ♦ ndarray.size — это общее количество элементов массива. Это произведение раз­ меров массива. ♦ ndarray.shape— кортеж целых чисел, в котором хранятся размеры массива по каждому измерению. Если у вас есть двумерный массив с 2 строками и 3 столбцами, форма вашего массива будет (2, 3). Например, давайте создадим массив: In [36]: array_example = np.array([[[0, 1, 2, 3], [4, 5, 6, 7]], [[О, 1, 2, 3], [4, 5, 6, 7]], [[О ,1 ,2, 3], [4, 5, 6, 7]]]) Чтобы узнать размерность массива, выполните следующий код: In [37]: array_example.ndim Out[37]: 3 Чтобы узнать общее количество элементов в массиве, выполните: In [38]: array_example.size Out[38] : 24 Чтобы найти форму вашего массива, выполните: In [39]: array_example.shape Out[39]: (3, 2, 4)
294 | Гпава 15 15.6. Изменение формы Метод ndarray.reshape о позволяет изменить форму массива без изменения данных. Просто помните, что, когда вы используете метод reshape)), массив, который вы хотите создать, должен содержать такое же количество элементов, что и исходный массив. Если вы меняете форму массива из 12 элементов, вам необходимо убедить­ ся, что ваш новый массив тоже будет содержать 12 элементов. Пусть у нас есть такой массив: In [40]: а = пр.агапде(б) print(а) | [0 1 2 3 4 5] Вы можете использовать метод reshaped для изменения формы вашего массива. Например, вы можете преобразовать его в массив из трех строк и двух столбцов: In [41]: Ь = a.reshape(3, 2) print(b) [[0 1] [2 3] [4 5]] Мы рассмотрели метод reshaped класса ndarray. А еще есть просто функция пр.reshaped с необязательными параметрами. In [42]: пр.reshape(a, newshape = (2, 3)) Out[42]: array)[[0, 1, 2], [3, 4, 5]]) In [43]: np.reshape (a, newshape = (2, 3), order='C) Out[43]: array) [[0, 1, 2], [3, 4, 5]]) In [44]: np.reshape(a, newshape = (2, 3), order='F') Out[44]: array)[[0, 2, 4], [1, 3, 5]]) In [45]: |put[45): np.reshape(a, newshape = 6, order='F') array([0, 1, 2, 3, 4, 5]) Здесь a — это массив, который нужно изменить. Параметр newshape— это новая форма, которая вам нужна. Вы можете передать целое число или кортеж целых чисел. Если вы укажете целое число, получите одно­ мерный массив такой длины. Для параметра order значение 'С' означает чтение/запись элементов с использова­ нием порядка индекса в стиле языка С; • F’ означает чтение/запись элементов с ис­ пользованием индекса в стиле языка Fortran. (Это необязательный параметр, его можно не указывать.)
Библиотека NumPy | 295 15.7. Добавление оси Размерность массива можно увеличить с помощью newaxis () и expand_dims (). Функция newaxis о позволяет увеличить размер вашего массива на одно измерение. Это означает, что одномерный массив станет двумерным, двумерный массив станет трехмерным и т. д. Пусть у нас есть такой массив: In [46]: а = np.array([1, 2, 3, 4, 5, 6]) а |out[46]: In [47]: |Out[47]: array([l, 2, 3, 4, 5, 6]) a.shape (6,) Вы можете использовать newaxis о для добавления новой оси: In [48]: а2 = a[np.newaxis, :] а2 |0ut[48]: array([[l, 2, 3, 4, 5, 6]]) С первого взгляда может показаться, что а и а2 одинаковые. Вид не изменился. Но если присмотреться более внимательно, то можно увидеть, что теперь в массиве есть одна дополнительная пара скобок [ ], показывающая, что появилась еще одна ось. Проверка формы массива подтвердит это. In [49]: | Out [49]: а2.shape (1, 6) Вы можете явно преобразовать одномерный массив в вектор-строку или в векторстолбец, используя newaxis(). Для преобразования одномерного массива в векторстроку добавьте ось в качестве первого измерения: In [50]: row_vector = a[np.newaxis, :] row_vector.shape |Out[50]: (1, 6) В случае вектор-столбца, вы можете вставить ось во втором измерении: In [51]: col_vector = а[:, np.newaxis] col_vector.shape |Out[51]; (6, 1) In [52]: col_vector Out[52]: array([[l], [2], [3], [4], [5], [6]])
296 Глава 15 | Можно использовать функцию дексом 1: In [53]: expand_dims(), чтобы добавить ось в позицию с ин­ b = np.expand_dims(a, axis=l) b.shape (6, 1) | Out [53]: А можно добавить ось в позицию с индексом 0: In [54]: с = np.expand_dims(a, axis=0) | Out [54]: с.shape (1, 6) 15.8. Индексирование и срезы У массивов NumPy есть индексы и срезы, как и у списков Python. In [55]: data = пр.array![1, 2, 3]) In [56]: data[0] 1 □ data[l] 2 □ Out[56]: In [57]: |Out[57]: data [0:2] In [58]: |Out[58] : array! [1, 2]) In [59]: data [ 1: ] |Out[59] : array! [2, 3]) data[-2:] In [60]: |Out[60]: array! [2, 3]) Схематично это выглядит так, как показано на рис. 15.6. 0 data data[0] 1 1 data(l) data[0:2] data[l:J data[-2:] 0 1 1 -2 1 1 2 2 3 2 2 2 2 -1 3 3 3 Рис. 15.6. Индексирование и срезы для одномерного массива Иногда нужно взять часть массива или его определенные элементы для дальнейше­ го анализа или дополнительной обработки. Для этого вам потребуется использовать подмножество, срез и/или индексы массива.
Библиотека NumPy | 297 Если требуется выбрать из массива значения, которые удовлетворяют определен­ ным условиям, то с NumPy это сделать проще всего. Например, пусть у нас есть массив: In [61]: а = пр.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) Вы можете легко вывести все элементы массива меньше 5: In [62]: print(а[а < 5]) | [1 2 3 4] Вы также можете выбрать числа, которые, например, больше или равны 5, и ис­ пользовать это условие в индексе массива: In [63]: | [ 5 6 five_up = (а >= 5) print(a[five_up]) 7 8 9 10 11 12] Вы можете выбрать элементы, которые делятся на 2: In [64]: | [ 2 4 divisible_by_two = а[а % 2 == 0] print(divisible_by_two) 6 8 10 12] Можно также выбрать элементы, которые удовлетворяют двум условиям, исполь­ зуя операторы & и |: In [65]: с = а[(а >2) & (а < 11)] print(с) | [ 3 4 6 5 7 8 9 10] Побитовые логические операторы & (И) и | (ИЛИ) можно использовать для получе­ ния логических значений, указывающих, соответствуют ли элементы массива определенному условию. Такой способ полезен для работы с массивами, в которых хранятся строки с именами или другими категориальными значениями. In [66]: five_up = (а > 5) | (а == 5) print(five_up) [ [False False False False] [ True True True True] [ True True True True]] Вы также можете использовать функцию дексов из массива. nonzero о для выбора элементов или ин­ Определим вот такой массив: In [67]: In а = пр.array([[1, 2, 3, 4], [68] : а Out[68]: array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) [5, 6, 7, 8], [9, 10, 11, 12]])
298 | Гпава 15 Вы можете использовать пример, меньше 5: In [69]: nonzero () для вывода индексов элементов, которые, на­ b = np.nonzero(a < 5) print(b) |(array([0, 0, 0, 0], dtype=int64), array([0, 1, 2, 3], dtype=int64)) В этом примере возвращается кортеж массивов: по одному для каждого измерения. Первый массив содержит индексы строк всех значений, удовлетворяющих усло­ вию, а второй массив — индексы столбцов этих значений. In [70]: print(а[b]) | [1 2 3 4] Если искомого элемента в массиве нет, то возвращаемый массив индексов будет пустым. Например: In [71]: not_there = np.nonzero(a == 42) print(not_there) |(array([], dtype=int64), array([], dtype=int64)) 15.9. Создание массива из существующих данных Вы можете легко создать новый массив из фрагмента уже существующего массива. Допустим, есть вот такой массив: In [72]: а = пр.аггау([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) Вы можете получить из него новый массив с помощью среза: In [73]: arrl = а[3:8] arrl |Out[73]: array([4, 5, 6, 7, 8]) Здесь вы взяли часть вашего массива с индекса 3 до индекса 8. Соединить два существующих массива можно как по вертикали, так и по горизон­ тали. Допустим, у вас есть два массива al и а2: In [74]: al = пр.array([[1, 1], [2, 2]]) а2 = пр.array([[3, 3], [4, 4]]) Вы можете соединить их вертикально с помощью vstack (): In [75]: пр.vstack((al, а2)) Out[75]: array![[1, 1], [2, 2], [3, 3], [4, 4]])
Библиотека NumPy Или по горизонтали с помощью In [76]: np.hstackf(al, a2)) Out[76] : array([[1, 1, 3, 3], | 299 hstackO: [2, 2, 4, 4]]) Вы можете разделить массив на несколько меньших массивов с помощью функции hsplit(). Вы можете указать либо количество возвращаемых массивов одинаковой формы, либо номера столбцов, после которых должно происходить деление. Допустим, есть массив: In [77]: х = np.arange(l, 25).reshape(2, 12) х Out[77]: array![[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]]) Если вы хотите разделить этот массив на три массива одинаковой формы, поможет вот такой код: In [78]: np.hsplit(х, 3) Out[78] : [array![ [ 1, 2, 3, 4], [13, 14, 15, 16]]), array! [[ 5, 6, 7, 8], [17, 18, 19, 20]]), array![[ 9, 10, 11, 12], [21, 22, 23, 24]])] Если вы хотите разделить массив после третьего и четвертого столбцов, выполните этот код: In [79]: np.hsplit(х, Out[79]: [array![[ 1, (3, 4)) 2, 3], [13, 14, 15]]), array![[ 4], [16]]), array([[ 5, 6, 7, 8, 9, 10, 11, 12], [17, 18, 19, 20, 21, 22, 23, 24]])] 15.10. Копии и представления массивов' При работе с массивами данные иногда копируются в новый массив, а иногда нет. Это часто сбивает с толку новичков. Есть три возможных варианта: 1. Простое присваивание (без копии). 2. Представление или неглубокая копия. 3. Копирование или глубокая копия. 1 SciPy, 2020 (https://numpy.org/devdocs/user/absolute_beginners.html) [45].
300 | Глава 15 15.10. 1. Присваивание без копии При простом присваивании объекты и их данные не копируются. In [80]: Out[80]: а = пр.аггау([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) Ь = а # новый объект не создается b is а # а и b - два имени одного и того же объекта ndarray True Python передает изменяемые объекты по ссылке, поэтому вызовы функций не ко­ пируются. In [81]: def f (х) : print(id(х)) id(a) # id - уникальный идентификатор объекта [2445066119408 In [82]: f (a) [2445066119408 15.10. 2. Представление или неглубокая копия В разных объектах массива могут использоваться одни и те же данные. Метод view () создает новый объект массива, который просматривает те же данные. In [83]: с = a.view() с is а Out[83]: False In [84]: c.base is a Out[84] : True # с - это представление массива a In [85]: c.flags.owndata Out[85]: False In [86]: c = c.reshape((2, 6)) # форма а при этом не изменится a.shape Out[86]: In [87] : (3, 4) # данные а изменятся c[0, 4] = 1234 a Out[87]: 0, 1, 2 [1234, 5, 6 8, 9, 10 array([[ [ 3], 7], 11]])
Библиотека NumPy | 301 Обратите внимание, что срез массива возвращает его представление. In [88]: s = а[:, 1:3] # s[:] - то же самое, что s. Обратите внимание з[:] = 10 # на разницу между з = 10 и s[:] =10 а Out [88]: array([[ 0, ю, 10, 3], [1234, 10, 10, 7], [ 10, ю, И]]) 8, 15.10. 3. Глубокая копия Метод ndarray.copy () делает полную копию массива и его данных. In [89]: d = a.copy!) # создается новый объект массива с новыми данными d is а |Out[89]: In [90]: |Out[90]: In [91]: False d.base is a # у массива d ничего нет общего с а False d[0, 0] = 9999 # изменение данных в d ничего не меняет внутри а a Out[91]: array([[ 0, 10, 10, 3], [1234, 10, 10, 7], 8, 10, ю, И]]) [ Иногда метод сору о следует вызывать после получения среза, если исходный мас­ сив больше не нужен. Предположим, что а — это объемный промежуточный мас­ сив, а конечный результат ь содержит только небольшую часть а. Тогда при по­ строении ь необходимо сделать глубокую копию: In [92]: а = np.arange(int(1е8)) b = а [: 100] .сору () del а # и тогда память массива а может быть освобождена Если вместо этого использовать просто ь = а[:100], то ь будет ссылаться на а массив а останется в памяти, даже если выполнить инструкцию del а. а, 15.11. Массивы NumPy в реальной жизни Мы рассмотрели, что такое массив NumPy и как его можно создать из различных типов данных. Но когда я впервые познакомился с NumPy, я несколько дней не мог понять, почему это так важно. Все говорят, что NumPy — самая важная библиоте­ ка, но в то же время в ней есть только матричные операции. Как они помогают решать реальные проблемы?
302 | Гпава 15 Когда я нашел ответ на этот вопрос, я очень обрадовался. Было приятно осознать, что почти все, что мы анализируем в повседневной жизни, при преобразовании в формат, понятный компьютеру, принимает формат многомерного массива (т. е. массива NumPy). Итак, давайте познакомимся с некоторыми из этих реальных объектов и их пред­ ставлением в матричном формате. Изображения, используемые в этом разделе, лю­ безно предоставлены Джеем Аламмаром из его блога1, в который можно зайти по ссылке: http://jalammar.github.io/visual-numpy/. Подумайте обо всех типах данных, с которыми вы сталкиваетесь каждый день, и постройте их модели (электронные таблицы, изображения, аудио и т. д.). Многие из них идеально подходят для представления в виде многомерного массива. 15.11.1. Электронные таблицы Excel Электронная таблица или таблица значений— это двумерная матрица. Каждый лист в Excel может быть отдельной переменной (рис. 15.7). Самая популярная абст­ ракция в Python для этого случая — это объект Pandas DataFrame, работа которого основана на NumPy. music.csv pandas.read_csv('music.csv') Artist Genre Listeners Plays 0 Billie Holiday Jazz 1,300.000 27.000,000 1 Jimi Hendrix Rock 2,700,000 70,000,000 2 Miles Davis Jazz 1,500,000 48.000,000 3 SIA Pop 2,000,000 74,000,000 Рис. 15.7. Преобразование данных Excel в двумерный массив 15.11.2. Аудиофайлы и временные ряды Аудиофайл — это одномерный массив семплов данных. Каждый семпл — это чис­ ло, представляющее собой крошечный фрагмент аудиосигнала. Звук в формате Audio CD записывается на скорости 44 100 семплов в секунду, и каждый семпл представляет собой целое число от -32 767 до 32 768. Это означает, что если у вас есть десятисекундный файл WAVE с качеством Audio CD, вы можете загрузить его в массив NumPy длиной 10 * 44 100 = 441 000 семплов. Если нужно получить пер­ вую секунду аудиофайла, просто загрузите файл в массив NumPy, который мы на­ зовем, например, audio, и возьмите срез audio[:44100]. 1 Alammar, 2019 (http://jalammar.github.io/visual-numpy/) [1].
Библиотека NumPy | 303 Рис. 15.8. Преобразование аудиофайла в одномерный массив NumPy Фрагмент аудиофайла показан на рис. 15.8. То же самое касается временных рядов (например, цены на акции). 15.11.3. Изображения Изображение — это матрица пикселов размером «высота х ширина». Если изображение черно-белое (т. е. в оттенках серого), каждый пиксел может быть представлен одним числом (обычно от 0 (черный) до 255 (белый)). Если вам нужно получить верхнюю левую часть изображения размером 10x10 пикселов, используя NumPy, достаточно взять срез [: 10, : 10]. Фрагмент файла изображения показан на рис. 15.9. Рис. 15.9. Преобразование изображения в оттенках серого в массив NumPy Если изображение цветное, то каждый пиксел представлен тремя числами, а имен­ но значениями красного, зеленого и синего компонентов (RGB). В этом случае нам нужно 3-е измерение (потому что каждая ячейка может содержать только одно чис­ ло). Итак, цветное изображение будет представлено трехмерным массивом разме­ ром «высота х ширина х 3» (рис. 15.10).
304 | Гпава 15 233 1188 137 96 90 95 73 73 82 237 202 159 120 105 110 88 107 112 121 109 63 226 191 147 110 101 112 98 123 110 119 142 131 221 191 176 182 203 214 169 144 133 145 155 122 185 160 161 184 205 223 186 137 147 161 140 115 181 174 189 207 206 215 194 136 142 151 133 87 246 237 237 231 208 206 192 122 143 144 111 74 254 254 241 224 199 192 181 99 122 117 107 74 239 248 232 207 187 182 184 110 114 110 113 74 193 215 193 167 158 164 181 114 112 111 105 82 113 119 110 111 113 123 135 120 108 106 113 \ 93 97 91 103 107 111 122 112 104 114 Рис. 15.10. Преобразование цветного изображения в массив NumPy 15.12. Резюме В этой главе мы познакомились с одной из самых мощных общедоступных библио­ тек Python. Она используется весьма часто, поскольку многие другие библиотеки, например Pandas, построены на базе NumPy. В NumPy вводится новый тип данных Python — массив ndarray. Как мы видели, массив NumPy работает быстрее и эффек­ тивнее по сравнению со списками Python. Кроме того, многие операции с массива­ ми могут выполняться только над массивами NumPy. У этих массивов более одной размерности, и они могут использоваться для представления сложных типов дан­ ных (например, аудиофайлов или изображений). В этой главе мы познакомились с основами NumPy, такими как: ♦ создание массива NumPy из случайных чисел, нулей или единиц; ♦ создание последовательностей с помощью функции arange (); ♦ добавление, сортировка и удаление элементов из массива; ♦ методы shape () и size() ДЛЯ массива; ♦ изменение формы массива; ♦ добавление оси в массив; ♦ индексирование и срезы элементов массива; ♦ создание массива из существующих данных; ♦ создание представлений и глубоких копий.
16 Операции в NumPy Эта глава служит продолжением предыдущей главы о NumPy, в которой мы позна­ комились с библиотекой NumPy и ее массивами. Узнали, как создавать массивы ndarray и использовать некоторые функции для работы с ними. В этой главе мы перейдем к изучению операций, выполняемых над массивами NumPy. Эта глава, как и предыдущая, опирается на документацию NumPy, в частности на руководство «NumPy: the absolute basics for beginners» сообщества SciPy1. 16.1. Основные операции над массивами Создав свой массив, вы можете начать работу с ним. Предположим, что мы создали два одномерных массива, один из которых называется data, а другой— ones (рис. 16.1). data ones 1 1 data = np.array![1,2]) ones = np.ones(2) 2 1 Рис. 16.1. Пример одномерных массивов NumPy Складывать массивы можно с помощью оператора + (рис. 16.2). In [1]: import numpy as пр data = np.array([1, 2]) ones = np.ones(2, dtype=int) |Out[1]: data + ones array![2, 3]) data ones data + ones Рис. 16.2. Сложение одномерных массивов 1 SciPy, 2020 (https://numpy.org/devdocs/user/absolute_beginners.html) [45].
306 | Гпава 16 Конечно, одним сложением дело не ограничивается (рис. 16.3)! In [2]: | Out [2]: data - ones array ([0, ID In [3]: [Out[3]: data * data array) [1, 4]? In [4]: |Out[4]: data / data array([!., l.D Арифметические операции над массивами выполняются поэлементно. При этом создается новый массив, который заполняется результатами. In [9]: а = np.array ([20, 30, 40, 50]) b = пр.arange(4) |Out[9]: In [10]: |Out[10]: In [11]: |Out[ll]: In [12]: Ь array([0, 1, 2, 3]) с = а - b с arrayt [20, 29, 38, 47D b * 2 array([0, 2, 4, 6]) 10 * np.sin(a) |put[12]: array([ 9.12945251, -9.88031624, In [13]: |Out[13]: a < 35 array([ True, 7.4511316, -2.62374854]) True, False, False]) В отличие от многих языков, предназначенных для работы с матрицами, оператор умножения * в NumPy выполняет именно поэлементное умножение одного массива на другой. А матричное умножение выполняется с помощью оператора @ (начиная с Python 3.5) или метода dot о. In [14]: А = np.array([[1, 1], [0, 1]]) В = пр.array([[2, 0], [3, 4]])
Операции в NumPy 307 # поэлементное умножение A * В Out[14]: | array! [[2, 0], [0, 4]]) # матричное умножение In [15]: A @ В Out[15]: array![[5, 4], [3, 4]]) # тоже матричное умножение In [16]: A.dot(B) Out[16]: array![[5, 4], [3, 4]]) 16.1.1. Универсальные функции В NumPy есть стандартные математические функции, такие как синус, косинус и экспонента. В NumPy они называются универсальными функциями (ufimc) и вы­ полняются поэлементно, создавая на выходе новый массив'. In [25]: В = пр.агапде(З) В |Out[25]: array! [0, 1, 2]) In [26]: | Out [26]: np.exp(B) In [27]: np.sqrt(B) |Out[27]: array! [0. In [28]: array! [1. , 2.71828183, 7.3890561 ]) , 1. , 1.41421356]) C = np.array([2., -1., 4.]) np.add(B, C) |Out[28]: array([2., 0., 6.]) Кроме упомянутых методов, попробуйте также использовать приведенные в табл. 16.1. Названия методов сами говорят об их функциональности — проверьте сами. ТАБЛИЦА 16.1 all () bincount() cumprod() lexsort() nonzero() sum!) any!) ceil() cumsum() max!) outer() trace() apply_along_axis() clip!) diff!) maximum () prod() transpose() argmax() conj() dot!) mean() re() var() argmin() corrcoef() floor!) median () round() vdot() argsort() cov() inner() mint) sort() vectorize!) average() cross() invert() minimum!) std() where() 1 SciPy, 2020 (https://numpy.org/devdocs/user/absolute_beginners.html) [45].
308 | Гпава 16 16.2. Транслирование Иногда вам может потребоваться выполнить математическую операцию между массивом и числом (т. е. между вектором и скаляром) или между массивами разных размеров. Например, у вас есть массив (назовем его data), содержащий информа­ цию о расстояниях в милях, но вы хотите преобразовать мили в километры. Это делается следующим образом (рис. 16.4): In [29]: |Out[29]: data = np.arrayf[1.0, 2.0]) data * 1.6 array) [1.6, 3.2]) 1 1 * 1.6 2 = 1.6 1.6 1.6 3.2 * 2 Рис. 16.4. Транслирование в NumPy NumPy понимает, что умножение выполняется над каждым элементом массива. Этот принцип называется транслирование. Транслирование массивов — это меха­ низм, который позволяет NumPy выполнять операции над массивами разной фор­ мы. Размеры массивов при этом должны быть совместимыми, т. е. размеры по об­ щим осям должны совпадать или один из них должен быть равен 1. Если размеры окажутся несовместимы, вы получите исключение ValueError. 16.3. Функции агрегирования В NumPy также есть функции агрегирования (рис. 16.5). В дополнение к стандарт­ ным функциям mini), max () и sum() есть также функция mean о, позволяющая полу­ чить среднее значение, prod(), выдающая результат умножения всех элементов, std(), вычисляющая стандартное отклонение, и многие другие. In [30]: |Out[3Q]: In [31]: |Out[31]: In [32]: |Out[32]: data data.max() 2.0 data.min() 1.0 data.sum() 3.0 data data 1 1 2 |.min() = 1 3 Рис. 16.5. Методы max (), min О и sum() для одномерного массива
Операции в NumPy | 309 16.4. Двумерные массивы Для создания двумерного массива (матрицы) в NumPy можно использовать списки списков Python (рис. 16.6). In [37]: data = пр.array([[1, 2], [3, 4]]) data Out[37]: array([[1, 2], [3, 4]]) np.array([[1,2],[3,4]]) Рис. 16.6. Создание матрицы При работе с матрицами полезны операции индексирования и срезы (рис. 16.7). In [38]: data = пр.array([[1, 2], data [0, 1] Out [38]: 2 In [39]: data[l:3] Out[39]: array([[3, 4], [3, 4], [5, 6]]) # первая строка и второй столбец # вторая и третья строки для всех столбцов [5, 6]]) In [40]: |0ut[40]: data(0:2, 0] array ([1, ~3]Т # с первой по вторую строку и первый столбец Функции агрегирования для матриц работают так же, как и для одномерных масси­ вов (рис. 16.8). In [41]: data.mint) |Out[41]: 1 In [42]: |Out[42]: data.maxO 7
310 | In [43]: |Out[43]: Глава 16 data.sumO 21 Рис. 16.8. Агрегирование для всех элементов матрицы По умолчанию функции агрегирования вычисляются для всех элементов матрицы, но можно также выполнить агрегирование по строкам или по столбцам (рис. 16.9). Для этого нужно указать, по какой оси вычислить функцию агрегирования: In [44]: |Out[44]: In [45]: |Out[45]: data.max(axis = 0) array([5, 6]) data.max (axis = 1) array([2, 4, 6]) data .max(axis-l) = Рис. 16.9. Агрегирование по строкам и столбцам Создав две матрицы одинакового размера, вы можете складывать и умножать их (рис. 16.10). In [46] : data = пр.array([[1, 2], [3, 4]]) ones = пр.array([[1, 1], [1, 1]]) data + ones Out[46]: array([[2, 3], [4, 5]]) data + ones Рис. 16.10. Матричная арифметика
Операции в NumPy | 311 Эти арифметические операции можно выполнять с матрицами разного размера, но тогда у одной из них должен быть только один столбец или одна строка. В этом случае NumPy применяет правила транслирования (рис. 16.11). In [47]: data = пр.array([[1, 2], [3, 4], [5, 6]]) ones_row = пр.array([[1, 1]]) data + ones_row Out[47]: array([[2, 3], [4, 5], [6, 7]]) data data 1 2 ones_row ones_row data + ones_row Рис. 16.11. Матричное транслирование 16.5. Уникальные элементы массива Найти уникальные элементы в массиве можно с помощью функции пр.unique (). Например, если у нас есть такой массив: а = пр.array([11, 11, 12, 13, 14, 15, 16, 17, 12, 13, 11, In [48]: 14, 18, 19, 20]) Мы можем использовать в этом массиве: In [49]: пр.unique о для вывода только уникальных значений unique_values = пр.unique(а) print(unique_values) | [11 12 13 14 15 16 17 18 19 20]~ Поиск уникальных значений в массиве используется довольно широко. Первое применение, которое приходит на ум, — это вывод списка «розничных отпускных цен» на все товары в продуктовом магазине стоимостью от 1 до 10 долларов. Таких предметов и цен могут быть тысячи. Но если вы возьмете уникальные значения, то получите лишь несколько уникальных ценовых категорий, например, 1 доллар, 1.5 доллара, 2 доллара и т. д. Чтобы получить индексы этих уникальных значений (т. е. получить массив первых позиций уникальных значений в массиве), просто передайте функции пр.unique о аргумент return index, а также второй массив. unique_values, indices_list = пр.unique(a, return_index=True) In [50]: | [ 0 2 3 print(indices_list) 4 5 6 7 12 13 14]
312 Глава 16 | In [51]: # возвращаются два массива, np.unique(a, return_index=True) # первый содержит уникальные значения, а второй — индексы (array([ll, 12, 13, 14, 15, 16, 17, 18, 19, 20]), Out [51]: array([ 0, 2, 3, 4, 5, 6, Передав функции пр.unique() аргумент вхождений этих уникальных значений. In [52]: 7, 12, 13, 14], dtype=int64)) return counts, вы можете узнать количество unique_values, occurrence_count = пр.unique(a, return_counts=True) print(occurrence_count) | [3 22211111 1] # возвращаются 3 массива, первый содержит уникальные значения, In [53]: # второй — индексы, третий — количество уникальных значений пр.unique(a, return_index=True, return_counts=True) (array([11, 12, 13, 14, 15, 16, 17, 18, 19, 20]), Out[53]: array([ 0, 2, 3, 4, 5, 7, 12, 13, 14], dtype=int64), 6, array([3, 2, 2, 2, 1, 1, 1, 1, 1, 1], dtype=int64)) Это также работает и с двумерными массивами! Возьмем такой массив: In [54]: a_2d = пр.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) a_2d Out[54]: array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12], ( 1, 2, 3, 4]]) Чтобы найти уникальные значения, выполним: unique_values = пр.unique(a_2d) In [55]: print(unique_values) |[ 1 2 3 5 4 6 7 8 9 10 11 12] Если ось не указана, двумерный массив превратится в одномерный. Если вы хотите получить уникальные строки или столбцы, обязательно передайте аргумент оси. Чтобы найти уникальные строки, используйте аргумент axis=o, а для столбцов укажите axis=l. In [56]: unique_rows = np.unique(a_2d, axis=0) print(unique_rows) [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] Чтобы получить уникальные строки, индексы и количество вхождений, выполните код:
Операции в NumPy In [57]: unique_rows, indexes, occurrence_count = np.unique(a_2d, In [58]: print(unique_rows) | 313 axis=O, return_counts=True, return_index=True) [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] In [59]: print(indexes) | [О 1 2] In [60]: | [2 1 1] print(occurrence_count) 16.6. Транспонирование и изменение формы матрицы Часто возникает необходимость транспонирования имеющейся матрицы. У масси­ вов NumPy есть свойство т, которое позволяет вам получить транспонированную матрицу (рис. 16.12). data 1 data.T 2 Рис. 16.12. Транспонирование матрицы In [61]: data Out[61]: array)[[1, 2], [3, 4], [5, 6]]) In [62]: data.T Out[62]: array([[l, 3, 5], [2, 4, 6]]) Вам также может потребоваться изменить размеры матрицы. Такая необходимость возникает, например, когда у вас есть функция, ожидающая определенную форму входных данных, отличную от имеющегося набора данных. В таких случаях будет полезен метод reshape (). Он принимает новые размеры матрицы, которые вам нуж­ ны (рис. 16.13). In [63]: data.reshape(2, 3) Out[63]: array([[l, 2, 3], [4, 5, 6]])
314 | Гпава 16 In [64]: data.reshape(3, 2) Out[64]: array([[l, 2], [3, 4], [5, 6]]) data data.reshape(3,2) 2 Рис. 16.13. Изменение формы матрицы Вы также можете использовать метод transpose (), чтобы транспонировать оси мас­ сива в соответствии с указанными вами значениями. Пусть есть вот такой массив: In [65]: arr = np.arange(6).reshape((2, 3)) arr Out[65]: array([[0, 1, 2], [3, 4, 5]]) Вы можете транспонировать его с помощью метода transpose (). In [66]: arr.transpose() Out[66]: array([[0, 3], [1, 4], [2, 5]]) 16.7. Обратный порядок элементов массива Функция NumPy пр. flip о позволяет менять порядок элементов на обратный или «переворачивать» содержимое массива вдоль оси. Функции пр.flip() нужно пере­ дать массив, который вы хотите перевернуть, и ось. Если вы не укажете ось, NumPy поменяет порядок элементов по всем осям вашего массива. Пусть есть одномерный массив: In [67]: arr = пр.array([1, 2, 3, 4, 5, 6, 7, 8]) Тогда его можно перевернуть: In [68]: |Out[68]: np.flip(arr) array([8, 7, 6, 5, 4, 3, 2, 1])
Операции в NumPy | 315 Двумерный массив переворачивается примерно так же. Например, возьмем массив: In [69]: arr_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) arr_2d Out[69]: array)[[ 1, 2, 3, 4b [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) Тогда все его строки и столбцы можно перевернуть: In [70]: reversed_arr = np.flip(arr_2d) print (reversed_arr) [[12 11 10 9] [ 8 7 6 5] [ 4 3 2 1]] Можно перевернуть только строки: In [71]: reversed_arr_rows = np.flip(arr_2d, axis=0) print(reversed_arr_rows) [[ 9 10 11 12] [ 5 6 7 8] [1234]] Или только столбцы: In [72]: reversed_arr_columns = np.flip(arr_2d, axis=l) print (reversed_arr_columns) [[4321] [ 8 7 6 [12 11 10 5] 9]] Вы также можете перевернуть содержимое только одного столбца или строки. На­ пример, требуется поменять порядок элементов только второй строки (строки с ин­ дексом 1): arr_2d[l] = np.flip(arr_2d[l]) In [73]: print(arr_2d) [[1234] [ 8 7 6 5] [ 9 10 11 12]] Вы также можете перевернуть второй столбец (с индексом 1): In [74]: arr_2d[:,l] = np.flip(arr_2d[:,1]) print(arr_2d) [[ 1 10 3 4] [ 8 7 6 5] [9 2 11 12]]
316 Глава 16 | 16.8. Сжатие многомерного массива в одномерный Под сжатием подразумевается преобразование многомерного массива в обычный одномерный массив. Есть два метода для сжатия массива: flatten () и ravel о. Основное различие между ними состоит в том, что одномерный массив, возвращаемый методом ravel (), явля­ ется ссылкой на исходный массив (т. е. представлением). Это означает, что любые изменения в новом массиве также повлияют и на исходный массив. Метод ravel () не создает копии данных, и поэтому эффективно использует память. Пусть имеется массив: In [75]: х = np.arrayd [1 , 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) X Out[75]: array! [[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) In [76]: x.flatten() |Out[76]: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) Когда вы используете метод flatten!), изменения в вашем новом массиве не по­ влияют на исходный массив. Например: In [77]: al = х.flatten!) al[0] = 99 # исходный массив print(x) [[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]] In [78]: print (al) |[99 2 3 4 5 6 7 8 9 10 11 12] А когда вы используете метод ravel о, изменения, которые вы вносите в новый мас­ сив, появятся и в исходном массиве. Например: а2 = х.ravel!) In [79]: а2[0] = 95 print(х) [[95 2 3 4] [ 5 6 7 8] # исходный массив [ 9 10 11 12]] In [80]: |[95 2 print(а2) 3 4 5 6 7 8 9 10 11 12]
Операции в NumPy | 317 16.9. Работа с математическими формулами Простота реализации математических формул для работы с массивами — одна из причин, благодаря которым NumPy так широко используется в научном сообщест­ ве Python. Возьмем для примера формулу вычисления среднеквадратичной ошибки (основная формула, используемая в моделях контролируемого машинного обучения, осно­ ванных на регрессии): ]"/ а\2 Реализовать эту формулу в NumPy просто и понятно: error = (1/п) * пр.sum(np.square(predictions - labels)) Дополнительным преимуществом является то, что массивы predictions и labels мо­ гут содержать одно или тысячу значений. Но важно только, чтобы они были одного размера. Это можно представить так, как показано на рис. 16.14. predictions 1 error = (1/3) * пр.sum(пр.square( labels 1 1 - 2 )) з 1 Рис. 16.14. Наглядное вычисление формулы, первый шаг В этом примере predictions и labels содержат три значения, т. е. п = 3. После вы­ полнения вычитания значения в полученном векторе возводятся в квадрат (рис. 16.15). Затем NumPy складывает значения (рис. 16.16), и в результате вы по­ лучаете значение ошибки для этого прогноза и оценку качества модели (рис. 16.17). е error = (1/3) * пр.sum(пр.square( -i -2 Рис. 16.15. Наглядное вычисление формулы, второй шаг 0 1 error = (1/3) * пр.sum( 4 Рис. 16.16. Наглядное вычисление формулы, третий шаг error = (1/3) * 5 Рис. 16.17. Наглядное вычисление формулы, последний шаг ))
318 | Глава 16 16.10. Сохранение массива в файл и чтение из файла В какой-то момент вам может потребоваться сохранить какие-нибудь массивы на диск и загрузить их обратно без повторного запуска кода. В NumPy есть несколько способов сохранять и загружать объекты. Объект ndarray можно сохранять в файл и загружать из файла с помощью функций пр.loadtxt () и пр. savetxt (), которые рабо­ тают с обычными текстовыми файлами, с помощью функций пр.load() и np.saveO, которые работают с двоичными файлами NumPy с расширением пру, а также есть функция np.savezf), которая сохраняет массивы в файлы NumPy с расширением npz. В файлах пру и npz хранятся данные, форма, dtype и другая информация, необхо­ димая для восстановления ndarray и позволяющая правильно извлечь массив, даже если файл был создан на другом компьютере с другой операционной системой. Если вы хотите записать один объект ndarray, сохраните его как файл пру с по­ мощью функции save(). Если вы хотите записать более одного объекта ndarray в одном файле, сохраните их в файл npz с помощью функции savez(). Вы также можете сохранить несколько массивов в один файл в сжатом формате npz с помо­ щью функции savez_compressed(). Для записи массива в функцию пр. save () нужно передать массив, который вы хоти­ те сохранить, и имя файла. Например, если вы создадите массив: In [81]: а = пр.array([1, 2, 3, 4, 5, 6]) вы можете сохранить его под именем filename.npy: In [82]: пр.save('filename1, а) Теперь, если вы откроете рабочую папку, вы найдете в ней новый файл с именем filename.npy. С помощью функции load () можно извлечь массив из файла: In [83]: b = пр.load('filename.пру') Теперь проверим: In [84]: print(b) | [1 2 3 4 5 6] Вы можете сохранить массив NumPy как простой текстовый файл, например файл csv или txt, с помощью функции savetxt (). Например, если вы создадите вот такой массив: In [85]: csv_arr = пр.array([1, 2, 3, 4, 5, 6, 7, 8]) Вы можете легко сохранить его в формате CSV с именем newfile.csv следующим образом: In [86]: пр.savetxt('new file.csv', csv arr)
Операции в NumPy | 319 Теперь, если вы войдете в свою рабочую папку, вы найдете в ней новый файл с именем newfile.csv. Вы можете быстро и легко загрузить сохраненный текстовый файл с помощью функции loadtxt (): In [87]: |Out[87]: np.loadtxt('new_flie.csv') array([l., 2., 3., 4., 5., 6., 7., 8.]) Функции savetxt о и loadtxt () принимают дополнительные необязательные пара­ метры, такие как верхний колонтитул, нижний колонтитул и разделитель. В то вре­ мя как текстовыми файлами проще обмениваться, файлы пру и npz имеют мень­ ший размер и быстрее читаются. 16.11. Резюме В этой главе вы рассмотрели операции над массивами NumPy. Сперва мы рассмот­ рели базовые операции, такие как сложение, вычитание и умножение массивов и матриц. Затем увидели универсальные функции, которые представляют собой раз­ ные математические операции. Транслирование в NumPy позволяет расширить меньший массив до размеров большего массива, чтобы можно было выполнить не­ обходимую операцию. Мы также рассмотрели и более полезные операции над мас­ сивами, такие как функции агрегирования, поиск уникальных элементов массивов и их индексов. Эти операции могут применяться ко всей матрице или к одной из осей. Мы также рассмотрели транспонирование и изменение формы матрицы. Ни­ чуть не сложнее перевернуть элементы массива или сжать массив. Объекты NumPy можно сохранять в файлы на компьютере или загружать их из файлов.
17 Библиотека Pandas 17.1. Введение в Pandas Что такое Pandas — ответ на данный вопрос от самих разработчиков можно найти на официальной стра­ нице. |ii| pandas Pandas — это библиотека с открытым исходным ко­ дом под лицензией BSD, в которой предоставляются высокопроизводительные и простые в использовании структуры данных и инструменты анализа данных для языка программирования Python1. Проще говоря, Pandas — это библиотека с открытым исходным кодом, построенная на основе библиотеки NumPy. В этой библиотеке есть различные структуры дан­ ных и операции для работы с числовыми данными и временными рядами. Эта биб­ лиотека популярна среди людей, занимающихся анализом данных. Pandas позволя­ ет упростить импорт данных. В ней есть функции для поиска, очистки, преобразо­ вания, визуализации и анализа данных. Pandas работает быстро, что обеспечивает высокую производительность конечного приложения. Само слово «Pandas» происходит от термина panel data (панельные данные) — эко­ нометрического термина, обозначающего наборы данных, которые содержат на­ блюдения за несколько периодов времени для одних и тех же компаний или людей. Эта глава вдохновлена и в значительной степени основана на уроках из официаль­ ного руководства Pandas. На официальном сайте Pandas pandas.pydata.org вы мо­ жете найти различные руководства для учащихся любого уровня. Я выбрал учебник для новичков и начал с самых основ Многие изображения в этой и следующей гла­ вах взяты со страницы «Getting started tutorials». 17.1.1. Зачем нам Pandas? Если вы собираетесь начать карьеру в Data Science, то одной из первых ваших це­ лей должно быть изучение Pandas. Этот инструмент, по сути, находится на перед­ нем фронте обработки ваших данных. Pandas позволяет импортировать внешние ' Pandas documentation, 2020 (https://pandas.pydata.Org/pandas-docs/version/l.0.4/getting_started/intro_tutorials/ index.html) [41].
322 | Глава 17 данные из различных источников и разных форматов в среду Python, находить ин­ формацию в данных, очищать, преобразовывать и анализировать их. Предположим, что вам нужно изучить набор данных, хранящийся на вашем ком­ пьютере в файле CSV. Pandas поможет извлечь данные из этого файла в DataFrame, а затем позволит вам: ♦ рассчитать статистику и получить информацию о данных, например: • каково среднее, медианное, максимальное и минимальное значения для каж­ дого столбца; • коррелирует ли столбец А со столбцом В; • как можно охарактеризовать распределение данных в столбце С; ♦ очистить данные, например, удалить пустые значения, отфильтровать строки или столбцы по заданным критериям; ♦ визуализировать данные с помощью Matplotlib, строить графики, линии, гисто­ граммы, пузырчатые диаграммы и многое другое; ♦ сохранить очищенные и преобразованные данные обратно в CSV или в любой другой формат или базу данных. Pandas является надстройкой над библиотекой NumPy, т. е. в Pandas используется или повторяется большая часть NumPy. Данные в Pandas часто используются для статистического анализа в SciPy, построения графиков функций в Matplotlib и алгоритмов машинного обучения в Scikit-learn'. В этой главе мы рассмотрим важную информацию о библиотеке Pandas, в том чис­ ле как ее установить, как использовать и как она работает с другими распростра­ ненными пакетами анализа данных Python, такими как Matplotlib. 17.1.2 . Установка и импорт Pandas Если вы устанавливали Python с использованием дистрибутива Anaconda, то Pandas уже установлена по умолчанию. Отдельно устанавливать Pandas не нужно, но на всякий случай вам полезно знать, как это сделать. Мы можем использовать один из двух менеджеров пакетов Conda или Pip. Открой­ те терминал (для пользователей MacOS) или командную строку (для пользователей Windows) и введите любую из следующих команд: conda install pandas или pip install pandas В качестве альтернативы, если вы работаете в Jupyter Notebook, вы можете запус­ тить вот такую команду: Ipip install pandas 1 McIntire G., Martin B., Washington L., 2020 (https://www.leamdatasci.com/tutorials/python-pandas-tutorialcomplete-introduction-for-beginners/ ) [7].
Библиотека Pandas | 323 Импортировать Pandas можно так же, как и NumPy: import pandas as pd 17.1.3 . Обработка данных в Pandas Если вы когда-либо пользовались программами для работы с электронными табли­ цами, например MS Excel или Libre Office Calc, вы имеете представление о работе с табличными данными. В Pandas есть новый тип данных, который позволяет весь­ ма удобно обрабатывать табличные данные в Python. Этот тип называется DataFrame (датафрейм). состоит из Series (серий). Каждый столбец в объект Series (рис. 17.1). DataFrame DataFrame представляет собой DataFrame Рис. 17.1. Столбцы Series в DataFrame в Pandas 17.2. Тип данных DataFrame 17.2.1. Создание DataFrame Существует много способов создать объект DataFrame. Его можно создать из различ­ ных входных данных, например списков, словарей, Series, массива NumPy, других DataFrame. Давайте создадим такой объект из словаря Python. Это продажи фруктов в продук­ товом магазине. In [1]: data = { "apples": "bananas": [4, 5, 8, 8, 9], [10, 6, 9, 3, 4] } |Out[l] : data {'apples': [4, 5, 8, 8, 9], 'bananas': [10, 6, 9, 3, 4]}
324 | Гпава 17 Конструктор DataFrame В Pandas вызывается С помощью Функции pd.DataFrame(). Давайте воспользуемся им для создания нового DataFrame. Но для начала нужно импортировать Pandas. In [2]: import pandas as pd pd.DataFrame(data) Out[2]: apples bananas 0 4 10 1 5 6 2 8 9 3 8 3 4 9 4 Если вы заметили, ключи словаря стали метками столбцов в табличных данных. Каждая пара «ключ — значение» из словаря преобразуется в столбец в DataFrame (т. е. в Series). 17.2.2. Индексы в DataFrame Есть еще одна вещь, о которой мы не сказали. Обратите внимание на индексы от О до 4 слева от первого столбца. Индексы автоматически создаются в Pandas, если мы не передаем значения для них сами. Индекс можно изменить в любой момент. На­ пример, это могут быть имена людей, купивших фрукты. Пусть в качестве индексов используются имена клиентов. In [3]: purchase = pd.DataFrame(data, index=["Peter", "Mathew", "Simon", "Rohit", "Sunil"]) In [4]: purchase apples bananas Peter 4 10 Mathew 5 6 Simon 8 9 Rohit 8 3 Sunil 9 4 Out[4]: Теперь мы можем посмотреть, кто какие фрукты в каком количестве купил. 17.2.3. Series в DataFrame В объекте purchase класса DataFrame есть два столбца. Их имена — это метки столб­ цов. Можно обращаться к ним по этим именам. При выборе одного столбца в DataFrame в Pandas возвращается объект обратиться к столбцу, укажите имя столбца в квадратных скобках [ ]. In [5]: Out[5]: purchase["apples"] Peter 4 Mathew 5 Series. Чтобы
Библиотека Pandas Simon | 325 8 Rohit 8 Sunil 9 Name: apples, dtype: int64 Этот объект Series также можно вынести в отдельную переменную. In [6]: banana = purchase["bananas"] banana Out[6]: Peter Mathew 10 6 Simon 9 Rohit 3 Sunil 4 Name: bananas, dtype: int64 Обратите внимание, что названия объектов в обоих случаях совпадают с именами столбцов. В начале этой главы мы также упомянули, что Pandas используется в анализе дан­ ных. Давайте рассмотрим несколько небольших фрагментов кода. 17.3. Столбцы DataFrame 17.3.1. Добавление столбца В существующий DataFrame можно добавить новый столбец. Это можно сделать с помощью несложного выражения. In [7]: purchase["oranges"] = pd.Series([8, 3, 9, 5, 2], index=["Peter", "Mathew", "Simon", "Rohit", "Sunil"]) purchase Out [7] : oranges apples bananas Peter 4 10 8 Mathew 5 6 3 Simon 8 9 9 Rohit 8 3 5 Sunil 9 4 2 Вставим еще один столбец, в котором будет содержаться количество всех куплен­ ных фруктов. In [8]: purchase["Total"] = purchase["apples"] + purchase["bananas"] + purchase["oranges"] purchase Out [8] : apples bananas oranges Total Peter 4 10 8 22 Mathew 5 6 3 14 Simon 8 9 9 26 Rohit 8 3 5 16 Sunil 9 4 2 15
326 | Глава 17 17.3.2. Удаление столбца Добавить новый столбец в Удалим столбец oranges. In [9]: было просто, и столь же просто удалить его. DataFrame del(purchase["oranges"]) purchase Out[9] : apples bananas Total Peter 4 10 22 Mathew 5 6 14 Simon 8 9 26 Rohit 8 3 16 Sunil 9 4 15 Вы должны также заметить, что удаление одного столбца не повлияло на осталь­ ные, включая столбец Total. 17.3.3. Изменение значений в столбце Значение данных в любом столбце можно изменить, присвоив тому же имени новое значение. In [10]: purchase["Total"] = purchase["apples"] + purchase["bananas"] purchase Out[10] : apples bananas Total Peter 4 10 14 Mathew 5 6 11 Simon 8 9 17 Rohit 8 3 11 Sunil 9 4 13 17.4. Строки DataFrame 17.4.1. Выбор строки К строкам в DataFrame можно обратиться двумя способами: ♦ по меткам строк. Если у строк есть метки, то можно обратиться по ним, используя метод 1ос [ ] (от англ, locate — найти). In [11]: Out[11] : purchase.loc["Peter"] apples 4 bananas 10 Total 14 Name: Peter , dtype: int64
Библиотека Pandas | 327 На выходе получим Series, у которого метками будут имена столбцов DataFrame. Именем Series будет метка строки, по которой выполнялось обращение; ♦ по численному индексу. Аналогично 1ос[] есть также метод iloc[], который принимает целочисленные аргументы и возвращает Series. Передаваемое целое число должно быть индек­ сом строки. In [12]: purchase.Hoc[2] Out[12]: apples 8 bananas 9 17 Total Name: Simon, dtype: int64 17.4.2. Срез строки (выбор нескольких строк) Выбор нескольких строк выполняется с помощью оператора :. In [13]: purchase[l:3] Out[13]: apples bananas Mathew 5 6 11 Simon 8 9 17 Total При выборке или взятии среза нескольких строк в качестве результата возвращает­ ся НОВЫЙ DataFrame. 17.5. Операции с DataFrame Над DataFrame или Series можно выполнять некоторые операции. В Pandas есть множество функций, каждая из которых является методом, которые можно приме­ нить к объекту DataFrame или к Series. Вызывая методы, не забывайте использовать круглые скобки (). Пример с методом max (): In [14]: | Out [14]: purchase["bananas"].max() Ip In [15]: |Out[15]: banana.max() 10 # Series Есть еще один полезный метод — describe (). Он возвращает сводную статистику по столбцам. Если есть несколько столбцов с текстовыми данными, они по умолчанию не учитываются в describe (). In [16]: purchase.describe () apples bananas Total count 5.000000 5.00000 5.00000 mean 6.800000 6.40000 13.20000 Out[16]:
328 | Глава 17 2.167948 3.04959 2.48998 min 4.000000 3.00000 11.00000 25% 5.000000 4.00000 11.00000 50% 8.000000 6.00000 13.00000 75% 8.000000 9.00000 14.00000 max 9.000000 10.00000 17.00000 std 17.6. Чтение данных из файла Вы можете использовать Pandas для чтения данных, хранящихся в файлах или на веб-странице. Для облегчения понимания и возможности воспроизведения и срав­ нения результатов в примерах я буду использовать общедоступный набор данных mpg.csv. Это один из наиболее часто используемых наборов данных для обучения основам обработки данных и Data Science. Скачать его можно по ссылке ниже: https://github.com/nilabhnishchhal/Python-Made-Easy/blob/master/mpg.csv Это ссылка на репозиторий GitHub. Открыв его, вы увидите кнопку Raw. Щелкните по ней правой кнопкой мыши и выберите команду Save link as (Сохранить ссылку как). Сохраните файл в рабочую папку на своем компьютере и измените его расши­ рение на csv. Теперь у вас на компьютере есть набор данных mpg.csv. Приступим к работе. Рис. 17.2. Чтение файла в Pandas Для чтения файлов различных форматов используются функции pd.read_*(), где * — это формат файла, который необходимо прочитать (рис. 17.2). Например, файл CSV можно прочитать с помощью функции pd.read_csv(). In [17]: mpg = pd. read_csv ("mpg. csv") mpg
Библиотека Pandas | 329 Out[17]: manufacturer model displ year cyl trans drv cty hwy fl class 0 audi a4 1.8 1999 4 auto(15) f 18 29 P compact 1 audi a4 1.8 1999 4 manual(m5) f 21 29 P compact 2 audi a4 2.0 2008 4 manual(m6) f 20 31 P compact 3 audi a4 2.0 2008 4 auto(av) f 21 30 P compact 4 audi a4 2.8 1999 6 auto(15) f 16 26 P compact 229 Volkswagen passat 2.0 2008 4 auto(s6) f 19 28 P midsize 230 Volkswagen passat 2.0 2008 4 manual(m6) f 21 29 P midsize 231 Volkswagen passat 2.8 1999 6 auto(15) f 16 26 P midsize 232 Volkswagen passat 2.8 1999 6 manual(m5) f 18 26 P midsize 233 Volkswagen passat 3.6 2008 6 auto(s6) f 17 26 P midsize [234 rows x 11 columns] Примечание Поскольку файл mpg.csv сохранен там же, где мой скрипт, в функции я использовал просто имя файла. Этот метод работает, даже если ваш файл mpg.csv находится в той же папке, что и документ Jupyter Notebook, с которым вы работаете. Если он на­ ходится в какой-либо другой папке или каталоге, вам необходимо передать в функцию полный путь к файлу. Обратите внимание, что мы не только импортировали данные из файла CSV в сре­ ду Python, но также присвоили их переменной с именем mpg. Переменная mpg указы­ вает на Dataframe, который содержит табличные данные из файла CSV. При вызове переменной она отображает Dataframe и выводит его на экран. Кроме того, внизу отображается количество строк и столбцов. В этом файле 234 строки и 11 столбцов. 17.6.1. Пояснение к данным из примера Вы получили Dataframe с 234 строками и 11 столбцами с данными об автомобилях. Пояснения к столбцам даны в табл. 17.1. ТАБЛИЦА 17.1 Столбец Описание manufacturer Производитель model Название модели displ Объем двигателя, в литрах year Год выпуска cyl Количество цилиндров trans Тип трансмиссии drv Тип трансмиссии, где f — передний привод, г — задний привод, 4 — полный привод
330 | Гпава 17 ТАБЛИЦА 17.1 (окончание) Столбец Описание cty Расход бензина в городе (пробег в милях на галлон) hwy Расход бензина на шоссе (пробег в милях на галлон) fl Тип топлива class Класс автомобиля 17.7. Запись данных в файл Методы to * () используются для сохранения данных из Pandas в файл соответст­ вующего формата (рис. 17.3). Метод to_excel() сохраняет данные в виде файла Excel. In [18]: mpg.to_excel('mpg.xlsx', sheet_name='cars', index=False) Теперь, когда вы откроете вашу рабочую папку, вы найдете там новый файл mpg.xlsx. Этот файл можно открыть с помощью MS Excel. —k ——k ——К csv xls HTML HDF5 3SON <> HF {} GBQ |_ SQL Рис. 17.3. Запись файла из Pandas Вы заметили, что вместо имени листа по умолчанию «Sheetl» используется имя листа — «cars». При установке index=Faise индексы строки в электронной таблице не сохраняются. Если вы хотите, чтобы индекс отображался в Excel, вы можете ус­ тановить параметр index=True. 17.8. Проверка DataFrame Методы head(), В DataFrame. tail О, info() и атрибут dtypes используются для проверки данных 17.8.1. Атрибут dtypes Проверить, как Pandas интерпретирует данные в каждом из столбцов, можно с по­ мощью атрибута Pandas dtypes.
Библиотека Pandas In [19]: mpg.dtypes Out[19]: manufacturer | 331 object model object displ float64 int64 year cyl int64 trans object drv object cty int64 hwy int64' fl object class object dtype: object Для каждого из столбцов выводится используемый тип данных. Типы данных в нашем DataFrame— целые числа (int64), числа с плавающей запятой (fioat64) и строки (object). 17.8.2. Метод info() Этот метод используется для получения краткого обзора данных DataFrame. In [20]: mpg.info() Cclass 'pandas.core.frame.DataFrame'> Rangeindex: 234 entries, 0 to 233 Data columns (total 11 columns): # Column 0 1 Non-Null Count Dtype manufacturer 234 non-null object model 234 non-null object 2 displ 234 non-null float64 3 year 234 non-null int 64 4 cyl 234 non-null int 64 5 trans 234 non-null object object 6 drv 234 non-null 7 cty 234 non-null int64 8 hwy 234 non-null int64 9 fl 234 non-null object 10 class 234 non-null object dtypes: float64(l), int64(4), object(6) memory usage: 20.2+ KB Примечание При выполнения запроса dtypes скобки не используются, т. к. dtypes — это атрибут DataFrame И Series. Атрибуты DataFrame ИЛИ Series ПИШУТСЯ без Скобок. Атрибуты првД- ставляют собой характеристику объекта, а метод (для которого требуются скобки) вы­ полняет определенные действия над объектом. В частности, info о — это метод.
332 Глава 17 | 17.8.3. Метод head() Этот метод возвращает несколько верхних строк объекта DataFrame. Если в метод head () ничего не передается, по умолчанию он выдает 5 верхних строк. Можно ото­ бразить большее или меньшее количество строк, передав нужное число в качестве аргумента этого метода. In [21]: mpg.headO Out[21]: manufacturer model displ year cyl trans drv cty hwy fl class audi audi a4 1.8 1999 4 1999 4 18 21 29 29 compact 1.8 f f P a4 auto(15) manual(m5) P compact a4 4 manual(m6) f 2008 4 auto(av) f 20 21 31 30 P a4 2.0 2.0 2008 3 audi audi P compact compact 4 audi a4 2.8 1999 6 auto(15) f 16 26 P compact 0 1 2 In [22] : # выведем первые 9 строк mpg.head(9) Out[22]: manufacturer model displ year cyl trans drv cty hwy fl class 0 audi a4 1.8 1999 4 auto(15) f 18 P 1 audi audi a4 1.8 1999 4 manual(m5) f 21 29 29 compact compact a4 2.0 2008 2.0 2008 manual(m6) auto(av) f f 20 21 P a4 4 4 31 30 P 4 audi audi a4 6 6 16 18 compact 1999 f f P a4 auto(15) manual(m5) 26 audi 2.8 2.8 1999 5 P compact 6 audi a4 3.1 2008 auto(av) f 18 P compact 7 audi audi a4 quattro 1.8 1999 6 4 26 27 manual(m5) 4 18 26 P compact a4 quattro 1.8 1999 4 auto(15) 4 16 25 P compact 2 3 8 Что если мы хотим увидеть последние строки DataFrame, P compact compact а не верхние? Вы наверняка уже догадались. 17.8.4. Метод tail() Чтобы увидеть последние строки, используйте метод In [23]: tail (). mpg.tail(7) Out[23]: manufacturer model displ year cyl trans drv cty hwy fl class 227 Volkswagen passat 1.8 1999 4 manual(m5) f 21 29 P midsize 228 Volkswagen passat auto(15) auto(s6) P P 230 volkswagen 2008 midsize Volkswagen passat 1999 6 P midsize 232 Volkswagen passat 2.8 1999 6 auto(15) manual(m5) 29 26 P 231 2.0 2.8 4 4 29 28 midsize passat passat f f 18 Volkswagen 1999 2008 4 229 1.8 2.0 233 Volkswagen passat 3.6 2008 6 auto(s6) manual(m6) midsize f f 19 21 16 f 18 26 P midsize f 17 26 P midsize
Библиотека Pandas | 333 17.9. Выбор части DataFrame 17.9.1. Выбор столбцов Допустим, вы хотите выполнить операции с моделью и годом производства авто­ мобилей. Взять из DataFrame всего два-три столбца проще простого (рис. 17.4). Ранее в этой главе мы видели, что для выбора одного столбца нужно использовать квад­ ратные скобки [ ], указав в них имя нужного столбца. Чтобы выбрать несколько столбцов, передайте список меток в квадратных скоб­ ках []. Рис. 17.4. Выбор столбцов In [24]: model_year = mpg[["manufacturer", "model", "year"]] model_year.head() Out [24]: year manufacturer model 0 audi a4 1999 1 audi a4 1999 2 audi a4 2008 3 audi a4 2008 4 audi a4 1999 Примечание Внутренние квадратные скобки обозначают список Python с именами столбцов, а внешние скобки используются для выбора данных из DataFrame, как было показано ранее В ЭТОЙ главе, КОГДа МЫ брали Series ИЗ DataFrame. Возвращаемый тип данных — тоже In [25]: |Out[25]7 type(model_year) pandas.core.frame.DataFrame In [26]: | Out [26]: model_year.shape (234, 3) DataFrame. Обратите внимание на форму полученного DataFrame. В нем 234 строки и 3 столбца. Объект DataFrame — это двумерный объект, первое измерение которого представля­ ет число строк, а второе измерение — число столбцов.
334 Глава 17 | 17.9.2. Выбор строк (фильтрация) Вы можете фильтровать строки по тем или иным критериями с помощью условных выражений (рис. 17.5). НН НН НН НН Hi НН Рис. 17.5. Фильтрация строк Например, если мы хотим отобрать только автомобили среднего размера, придется написать вот так: In [27]: midsize = mpg[mpg["class"] == "midsize"] midsize.head() Out[27]: manufacturer model displ year cyl trans drv cty hwy fl class 15 audi a6 quattro 2.8 1999 6 auto(15) 4 15 24 P midsize 16 audi a6 quattro 3.1 2008 6 auto(s6) 4 17 25 P midsize 17 audi a6 quattro 4.2 2008 8 auto(s6) 4 16 23 Chevrolet malibu 2.4 1999 4 auto(14) f 19 27 P r midsize 32 33 Chevrolet malibu 2.4 2008 4 auto(14) f 22 30 r midsize midsize Давайте разберемся, что здесь произошло. Когда мы передали условие mpg["class"] == "midsize", Pandas создает Series с логи­ ческими значениями. Он проверяет условие для каждой строки в указанном столб­ це и возвращает True или False в зависимости от того, выполняется условие или нет. Таким образом, True возвращается для каждого столбца со значением "midsize", а для остальных — False. Давайте рассмотрим пример ниже: In [28]: mpgf'class"] == "midsize" Out[28]: 0 False 1 False 2 False 3 False 4 False 229 True 230 True
Библиотека Pandas 231 True 232 True 233 True | 335 Name: class, Length: 234, citype: bool Также обратите внимание, что такой Series имеет ту же длину, что и исходный объ­ ект DataFrame. Таким образом, в каждой строке есть одно значение True или False. Теперь такой Series с логическими значениями можно использовать для фильтра­ ции DataFrame, указав его в квадратных скобках []. Будут выбраны только строки, для которых установлено значение True. Таким образом, выбираются только строки, в которых класс автомобиля равен "midsize", и мы получили новый DataFrame с названием midsize. Давайте посмотрим, сколько автомобилей среднего размера отобралось из 234 автомобилей. In [29]: |Out[29]: midsize.shape (41, 11) Среди 234 автомобилей в списке присутствует 41 автомобиль среднего размера (т. К. В НОВОМ DataFrame 41 строка). Вы можете использовать и другие операторы, такие как >, >=, с, <=. Чтобы ука­ зать более одного условия, мы можем использовать операторы | и &. Например, выведем только внедорожники 1999 года выпуска. In [30]: suv_99 = mpg[(mpg["class"] == "suv") & (mpg["year"] == 1999)] suv_99.head() Out[30]: manufacturer model displ year cyl trans drv cty hwy fl 21 Chevrolet C1500 suburban 2wd 5.7 1999 8 auto(14) r 13 17 r SUV 30 Chevrolet kl500 tahoe 4wd 5.7 1999 8 auto(14) 4 11 15 r SUV class 31 Chevrolet kl500 tahoe 4wd 6.5 1999 4 14 17 d SUV dodge durango 4wd 3.9 1999 8 6 auto(14) 57 auto(14) 4 13 17 r SUV 61 dodge durango 4wd 5.2 1999 8 auto(14) 4 11 16 r SUV Примечание При объединении нескольких условных операторов каждое условие должно быть за­ ключено в круглые скобки о. Более того, вы не можете вместо символов | и & исполь­ зовать слова or и and. 17.9.3. Выбор строк и столбцов Как выбрать определенные строки и столбцы из DataFrame (рис. 17.6)? Давайте выведем названия моделей автомобилей, выпущенных после 2000 года. In [31]: model_00 = mpg.loc[mpg["year"] > 2000, "model"] model_00.head()
336 Гпава 17 | Out[31]: 2 а4 3 а4 6 а4 9 а4 quattro 10 а4 quattro Name: model, dtype: object В этом случае подмножество строк и столбцов создается за один раз, и простого использования скобок [] уже недостаточно. Обязательно нужно использовать ме­ тоды 1ос[] или Нос[]. При их использовании в качестве первого параметра указы­ вают нужные строки, а второй параметр — это нужные столбцы. Рис. 17.6. Выбор и строк, и столбцов При использовании имен столбцов, меток строк или условных выражений исполь­ зуйте метод 1ос [ ]. В этом случае в качестве параметров можно указать одну метку, список меток, фрагмент меток, условное выражение или простое двоеточие (:). Использование двоеточия указывает, что вы хотите выбрать все строки или все столбцы. Что, если мы хотим выбрать несколько строк или столбцов по индексам? В этом случае мы используем метод Нос [ ]. Выберем строки с 8-й по 18-ю и столбцы с 4-го по 6-й. In [32]: cyl mpg.Нос[8:19, 4:7] trans drv 8 4 auto (15) 4 9 4 manual(m6) 4 10 4 auto(s6) 4 11 6 auto (15) 4 12 6 manual(m5) 4 13 6 auto(s6) 4 14 6 manual(m6) 4 15 6 auto(15) 4 16 6 auto(s6) 4 17 8 auto (s6) 4 18 8 auto (14) r Опять же, подмножество строк и столбцов создается за один раз, и простого ис­ пользования скобок выбора (] уже недостаточно.
Библиотека Pandas | 337 17.10. Резюме В этой главе мы познакомились с еще одним полезным пакетом Python — обще­ доступной библиотекой, основанной на NumPy, под названием Pandas. Это один из самых полезных пакетов для задач анализа данных. Импортировать пакет можно с помощью оператора import pandas as pd. Таблица данных в Pandas представляется классом DataFrame. Каждый столбец в DataFrame представляет собой объект Series. Работа с данными осуществляется через применение методов DataFrame или Series. В Pandas реализовано получение данных из множества различных форматов файлов или источников данных с помощью функций read * о. Экспорт данных из Pandas осуществляется методами to_*(). Методы head(), tail О, info О и атрибут dtypes по­ зволяют проверить даннные. Для выбора подмножества данных используются квадратные скобки [ ]. Внутри этих скобок вы можете использовать метку столбца или строки, список с метками необходимых столбцов или строк, срез, условное вы­ ражение или двоеточие. Чтобы выбрать определенные строки и столбцы, исполь­ зуйте метод 1ос [ ] и имена строк и столбцов. Для выбора определенных строк и/или столбцов по индексам используйте метод Пос[]. Методы 1ос[] и iloc[] можно ис­ пользовать многократно.
18 Pandas в действии Продолжим работу с набором данных об автомобилях. Вы, конечно, можете по­ практиковаться с любым другим набором данных. Но я предлагаю использовать тот же набор данных mpg, который мы создали в главе 17, чтобы можно было легко сравнить результаты, а затем поэкспериментировать с кодом. In [1]: import pandas as pd mpg = pd.read_csv("mpg.csv", index_col=0) mpg. head () |Out[l]: manufacturer model displ year cyl trans drv cty hwy fl class audi a4 1.8 1999 4 auto(15) a4 1.8 1999 4 manual(m5) 18 21 29 29 P audi f f compact compact audi a4 2.0 2008 4 manual(m6) f a4 2.0 2008 4 auto(av) f 31 30 P audi 20 21 P compact compact audi a4 2.8 1999 6 auto(15) f 16 26 P compact P 18.1. Добавление столбца Добавим в Dataframe еще один столбец. Столбцы cty и hwy — это расход бензина, когда автомобиль движется по городу или по шоссе соответственно. Давайте соз­ дадим еще один столбец, в котором будет рассчитано соотношение «пробега по шоссе» к «пробегу по городу». In [2]: mpg["hwy_vs_cty"] = mpg["hwy"] / mpg["cty"] mpg. head () Out[2] : manufacturer model displ year cyl trans drv cty hwy fl class hwy_vs_cty audi audi a4 a4 a4 1.8 1999 4 f 1.8 1999 4 auto(15) manual(m5) f 18 21 29 29 P P compact compact 1.611111 1.380952 2.0 2008 4 manual(m6) f 20 31 P compact a4 a4 2.0 2008 21 30 P compact 1.550000 1.428571 1999 auto(av) auto(15) f 2.8 4 6 f 16 26 P compact 1.625000 audi audi audi Обратите внимание, что мы указали только одно выражение с метками столбцов, а операция применилась ко всем строкам. Вот где вся сила Pandas — не нужно ис­ пользовать циклы для перебора всех строк!
340 | Гпава 18 18.2. Удаление столбцов В DataFrame могут содержаться данные, которые вам вообще не нужны. Вы можете легко удалить весь столбец и изменить DataFrame. In [3]: del (mpg["hwy_vs_cty"]) mpg.head() Out[3]: manufacturer model displ year cyl trans drv cty hwy fl class audi a4 1.8 1999 4 auto(15) f 18 29 P compact audi a4 1.8 1999 4 manual(m5) f 21 29 P compact audi a4 2.0 2008 4 manual(m6) f 20 31 P compact audi a4 2.0 2008 4 auto(av) f 21 30 P compact audi a4 2.8 1999 6 auto(15) f 16 26 P compact 18.3. Переименование столбцов Существует также возможность переименовать некоторые или все столбцы. Вы можете изменить метку столбца в том же DataFrame или создать новый. Здесь мы создадим другой DataFrame, чтобы исходный остался без изменений. In [4]: mpg_l = mpg.rename(columns={"cyl":"cylinder", "trans":"transmission"}) mpg_l.head() Out [4]: manufacturer model displ year cylinder transmission drv cty hwy fl class audi a4 1.8 1999 4 auto(15) f 18 29 P compact audi a4 1.8 1999 4 manual(m5) f 21 29 P compact audi a4 2.0 2008 4 manual(m6) f 20 31 P compact audi a4 2008 4 auto(av) f 21 30 P compact audi a4 2.0 2.8 1999 6 auto(15) f 16 26 P compact Функцию rename о можно использовать как для изменения меток столбцов, так и для изменения меток строк (индексов). Для этого нужно передать в качестве аргу­ мента словарь, в котором ключи — это текущие метки, а значения — это новые метки соответствующих элементов1. Изменить метки можно не только на фиксированные имена, а можно применить некоторую функцию сопоставления. Например, преобразование имен столбцов в верхний регистр можно выполнить с помощью функции: In [5]: mpg_l = mpg_l.rename(columns=str.upper) mpg_l.head() 1 Pandas documentation, 2020 (https://pandas.pydata.Org/pandas-docs/version/l.0.4/getting_started/intro_tutorials/ index.html) [41].
Pandas в действии | 341 Out[5]: manufacturer MODEL DISPL YEAR CYLINDER TRANSMISSION DRV CTY HWY FL CLASS audi a4 1.8 1999 4 auto(15) f 18 29 P compact audi a4 1.8 1999 4 manual(m5) f 21 29 P compact audi a4 2.0 2008 4 manual(m6) f 20 31 P compact audi a4 2.0 2008 4 auto(av) f 21 30 P compact audi a4 2.8 1999 6 auto(15) f 16 26 P compact Вы также могли заметить, что, в отличие от предыдущего примера, где мы создали новый DataFrame с переименованными столбцами, здесь мы внесли изменения в тот же DataFrame. 18.4. Сводная статистика В Pandas легко получить сводную статистику и получить стандартные статистиче­ ские показатели по любому числовому столбцу. Давайте узнаем средний пробег всех машин в городе. In [6]: |Out[6]: mpg["cty"] .meant) 167858974358974358 К столбцам с числовыми данными можно применять разные статистические метри­ ки. Обычно в таких операциях исключаются отсутствующие данные, и по умолча­ нию они вычисляются для всех строк (рис. 18.1). Рис. 18.1. Сводная статистика по столбцам Давайте узнаем медиану для пробега всех автомобилей в городе и на шоссе. In [7]: Out[7] : mpg[["cty", "hwy"]].mediant) cty 17.0 hwy 24.0 dtype: float64 Статистика, применяемая к нескольким столбцам DataFrame (выбор двух столбцов возвращает DataFrame), вычисляется для каждого столбца. Можно рассчитать сводную статистику для нескольких столбцов одновременно. Давайте посмотрим, как метод describe о сработает одновременно для нескольких столбцов. In [8]: mpg[["cty", "hwy"]].describe()
342 | Глава 18 Out[8]: cty count hwy 234.000000 234.000000 16.858974 23.440171 mean std 4.255946 5.954643 min 9.000000 12.000000 25% 14.000000 18.000000 50% 17.000000 24.000000 75% 19.000000 27.000000 max 35.000000 44.000000 Вместо фиксированного списка статистик можно получить только указанные ста­ тистики для заданных столбцов с помощью метода agg (). In [9]: mpg.agg({'cty': ['min', 'max', 'median', 'skew'], 'hwy': ['min', 'max', 'median', 'mean']}) cty Out[9]: max 44.000000 NaN 23.440171 mean median hwy 35.000000 17.000000 24.000000 min 9.000000 12.000000 skew 0.796561 NaN 18.5. Группировка по категориям В Pandas статистические методы, как и многие другие, можно применить к данным DataFrame, предварительно сгруппированным по категориям. Рассмотрим эту воз­ можность на примере следующего вопроса. Что если мне нужно узнать, сколько существует типов цилиндров? И сколько машин в каждой группе? Давайте получим ответы на эти вопросы, а затем перейдем к более сложным. In [10]: mpg.groupby("cyl").count() Out[10]: cyl model displ year trans drv cty hwy fl class 4 81 81 81 81 81 81 81 81 81 5 4 4 4 4 4 4 4 4 4 6 79 79 79 79 79 79 79 79 79 8 70 70 70 70 70 70 70 70 70 Мы узнали, что есть 81 автомобиль с 4-цилиндровыми двигателями, 4 автомобиля с 5-цилиндровыми двигателями, 79 автомобилей с 6-цилиндровыми двигателями и 70 автомобилей с 8-цилиндровыми двигателями. Интересно, а почему существует только один вариант двигателя с нечетным ци­ линдром? И почему 5-цилиндровый двигатель не так популярен, как другие вари­ анты с четным номером?
Pandas в действии | 343 Знания открываются лишь тем, кто задает правильные вопросы. И мы прямо сейчас увидели пример того, как анализ данных позволяет формулировать правильные во­ просы. Вернемся к первоначальному вопросу: как узнать, сколько типов цилиндров суще­ ствует и сколько автомобилей находится в каждой группе? Нам бы не хотелось получать лишнюю информацию от всех столбцов, поэтому давайте просто посчитаем, сколько моделей было в каждой категории. In [ 11]: mpg[["cyl", "model"]].groupby("cyl").count() Out[11]: model cyl 4 81 5 4 6 79 8 70 To, что мы здесь сделали, называется split-apply-combine (разделение-применениеобъединение): ♦ разделяем данные на группы; ♦ применяем некоторые операции к каждой из этих групп; ♦ объединяем результаты. Схематично эти шаги выглядят так, как показано на рис. 18.2. Рис. 18.2. Стратегия «разделение-применение-объединение» Как получить средний пробег автомобилей по количеству цилиндров и в городе, и на шоссе? In [12]: mpg[["cty", "hwy", "cyl"]].groupby("cyl").meant) cty hwy 4 21.012346 28.802469 5 20.500000 28.750000 6 16.215190 22.822785 8 12.571429 17.628571 Out[12]: cyl
344 | Гпава 18 И снова человеку, который плохо разбирается в том, как количество цилиндров влияет на пробег, помогут приведенные выше данные. Теперь вы можете задать правильный вопрос. Почему пробег обратно пропорционален количеству цилиндров? Что ж, я отвечать на этот вопрос не буду, т. к. цель состояла лишь в том, чтобы вы могли задать правильный вопрос. Но если вы сами поищете ответ на этот вопрос, он покажется вам поразительно интересным и очевидным. Поскольку нас интересует средний пробег для каждого типа двигателя, выбранного по количеству цилиндров, сначала мы делаем выборку из трех столбцов: mpg[["cty", "hwy", "cyl"]]. Затем к столбцу cyl применяется метод groupbyO, чтобы сгруппиро­ вать значения по категориям. Наконец, вычисляется и возвращается средний пробег для каждой категории. Если нас интересует только средний пробег для каждого цилиндра, то для сгруппи­ рованных данных также поддерживается выбор столбцов (квадратные скобки [ ], как обычно) (рис. 18.3). In [13]: mpg.groupby("cyl")["cty"].mean() Out [13]: cyl 4 21.012346 5 20.500000 6 16.215190 8 12.571429 Name: cty, dtype: float64 .mean() mpg Рис. 18.3. Группировка и выбор столбцов Каков средний городской пробег для 6-цилиндрового двигателя среди внедорожни­ ков и 4-цилиндрового двигателя среди переднеприводных автомобилей? Мы можем применить группировку более чем к одному столбцу. In [14]: mpg.groupby(["cyl", "drv"])["cty"].mean() Out[14]: cyl drv 4 4 18.347826 f 22.068966 5 f 20.500000 6 4 14.781250 f 17.186047 r 17.250000
Pandas в действии 8 4 12.104167 f 16.000000 г 13.476190 | 345 Name: cty, citype: float64 Группировку можно производить по нескольким столбцам одновременно. Для это­ го нужно передать имена столбцов в виде списка методу groupby (). 18.6. Сортировка строк Мы можем отсортировать данные в порядке возрастания или убывания любого столбца или даже нескольких столбцов. Давайте отсортируем данные по объему двигателя в возрастающем порядке. In [15]: mpg.sort values(by="displ").head() Out[15] : manufacturer model displ year cyl trans drv cty hwy fl class honda civic 1.6 1999 4 manual(m5) f 28 33 r subcompact honda civic 1.6 1999 4 manual(m5) f 25 32 r subcompact honda civic 1.6 1999 4 manual(m5) f 23 29 subcompact honda civic 1.6 1999 4 auto(14) f 24 32 p r honda civic 1.6 1999 4 auto(14) f 24 32 r subcompact subcompact Давайте рассмотрим те же данные, отсортированные по расходу на шоссе, а затем по объему двигателя в порядке убывания. In [16]: mpg.sort values(by=["hwy", "displ"], ascending=False).head() Out [16]: manufacturer model displ year cyl trans drv cty hwy fl class d compact subcompact 1.9 1999 4 manual(m5) f 33 44 new beetle 1.9 1999 4 manual(m5) f 35 44 d new beetle 1.9 1999 4 auto(14) f 29 41 d subcompact toyota corolla 1.8 2008 4 manual(m5) f 28 37 r compact honda civic 1.8 2008 4 auto(15) f 25 36 r subcompact Volkswagen Volkswagen Volkswagen jetta С помощью метода sort values о строки в таблице сортируются по определенным столбцам. Индекс соответствует порядку строк. 18.7. Объединение данных из нескольких таблиц Сперва создадим три таблицы из одних и тех же данных о расходе топлива. В реальной жизни у вас будут разные таблицы, которые нужно будет объединять для дальнейшего анализа. Для простоты понимания и использования создадим 3 таблицы из одного набора данных.
346 | Гпава 18 In [17]: mpg_4 = mpg[mpg["drv"] == "4"] mpg_f = mpg[mpg["drv"] == "f"] mpg_r = mpg[mpg["drv"] == "r"] In [18]: mpg_4.head() Out[18]: manufacturer model displ year cyl trans drv cty hwy fl class audi a4 quattro 1.8 1999 4 manual(m5) 4 18 26 P compact audi a4 quattro 1.8 1999 4 auto(15) 4 16 25 P compact audi a4 quattro 2.0 2008 4 manual(m6) 4 20 28 P compact audi a4 quattro 2.0 2008 4 auto(s6) 4 19 27 P compact audi a4 quattro 2.8 1999 6 auto(15) 4 15 25 P compact In [19]: mpg_r.head() Out [19] : manufacturer model displ year cyl trans drv cty hwy fl class Chevrolet C1500 suburban 2wd 5.3 2008 8 auto(14) r 14 20 r SUV Chevrolet cl500 suburban 2wd 5.3 2008 8 auto(14) r 11 15 e SUV Chevrolet C1500 suburban 2wd 2008 8 auto(14) r 14 20 r SUV Chevrolet C1500 suburban 2wd 5.3 5.7 1999 8 auto(14) r 13 17 r SUV Chevrolet C1500 suburban 2wd 6.0 2008 8 auto(14) r 12 17 r SUV In [20]: mpg_f.head() Out [20] : manufacturer model displ year cyl trans drv cty hwy fl class audi a4 1.8 1999 4 auto(15) f 18 29 P compact audi a4 1.8 1999 4 manual(m5) f 21 29 P compact audi a4 2.0 2008 4 manual(m6) f 20 31 P compact audi a4 2.0 2008 4 auto(av) f 21 30 P compact audi a4 2.8 1999 6 auto(15) f 16 26 P compact Теперь у нас есть 3 разных In [21]: DataFrame или таблицы, форма которых показана ниже. print(mpg_4.shape) print(mpg_f.shape) print(mpg r.shape) (103, 10) (106, 10) (25, 10) 18.7.1. Объединение объектов Мы уже выполняли конкатенацию в строках и списках, и ту же концепцию можно применять К DataFrame (рис. 18.4). Давайте посмотрим, как объединить данные из двух pd.concat (). DataFrame с помощью функции
Pandas в действии In [22]: mpg_all = pd.concat([mpg_4, mpg_f, mpg_r], axis=0) In [23]: mpg all | 347 Out[23]: manufacturer model diepi year cyl trans drv cty hwy fl class audi a4 quattro 1.8 1999 4 manual(m5) 4 18 26 P compact audi a4 quattro 1.8 1999 4 auto(15) 4 16 25 P compact audi a4 quattro 2.0 2008 4 manual(m6) 4 20 28 P compact audi a4 quattro 2.0 2008 4 auto(s6) 4 19 27 P compact audi a4 quattro 2.8 1999 6 auto(15) 4 15 25 P compact ford mustang 4.6 2008 8 auto(15) r 15 22 r subcompact ford mustang 5.4 2008 8 manual(m6) r 14 20 subcompact lincoln navigator 2wd 5.4 1999 8 auto(14) r 11 17 p r lincoln navigator 2wd 5.4 1999 8 auto(14) r 11 16 SUV lincoln navigator 2wd 5.4 2008 8 auto(16) r 12 18 p r SUV SUV [234 rows x 10 columns] принимает в качестве входных данных список из нескольких DataFrame, а затем объединяет их по указанной оси. Как вы помните, значение оси для строки (вертикальная ось) равно 0, а для столбца (горизонтальная ось) — 1. pd.concat о Здесь, как вы могли заметить, после объединения в (103 + 106 + 25) и 10 столбцов. mpg aii получилось 234 строк Если вы ранее использовали какую-либо программу для работы с электронными таблицами, например Excel, эта операция похожа на объединение строк путем со­ поставления столбцов. 18.7.2. Объединение с использованием общего идентификатора Если бы вы использовали Microsoft Excel для работы с электронными таблицами, то для соединения столбцов из двух разных таблиц по общему идентификатору вы, возможно, использовали бы функцию viookup (). В эту функцию передается иденти-
348 Гпава 18 | фикатор, который мы «ищем» в таблицах Excel. В Pandas эта же операция реализо­ вана намного мощнее и гибче. В наборе данных об автомобилях нет ни одного столбца с уникальными значения­ ми. Следовательно, присоединение с использованием любого из них приведет к ошибкам. И поэтому мы воспользуемся набором данных Titanic, но разделим его на два новых набора с выбранными столбцами, чтобы продемонстрировать, как их можно объединить с помощью общего идентификатора. В качестве общего идентификатора будем использовать столбец Name. Вы можете скачать таблицу по ссылке ниже: https://github.com/nilabhnishchhal/Python-Made-Easy/blob/master/titanic.csv Это ссылка на репозиторий GitHub. На открывшейся странице найдите кнопку Raw, щелкните по ней правой кнопкой мыши и выберите Save link as. Сохраните файл в рабочей папке на вашем компьютере и измените его расширение на csv. Теперь в базовой папке вашего компьютера есть набор данных titanic.csv. Давайте поработаем над ним. In [24]: titanic = pd.read_csv("titanic.csv") titanic.head() Out[24]: Passengerld Survived Pclass 0 1 0 3 1 2 1 1 2 3 1 3 3 4 1 1 5 0 3 4 \ Age SibSp \ Name Sex Braund, Mr. Owen Harris male 22.0 1 1 Cumings , Mrs. John Bradley (Florence Briggs Th... female 38.0 1 2 Heikkinen, Miss. Laina female 26.0 0 3 Futrelle, Mrs. Jacgues Heath (Lily May Peel) female 35.0 1 35.0 0 0 Allen, Mr. William Henry 4 Fare Cabin Embarked Parch Ticket 0 0 A/5 21171 7.2500 NaN S 1 0 PC 17599 71.2833 C85 C 2 0 STON/O2 . 3101282 7.9250 NaN S 3 0 113803 53.1000 C123 S 4 0 373450 8.0500 NaN S In [25]: datasetl = titanic!["Name", "Sex", "Age"]] datasetl male
Pandas в действии | 349 Out[25]: Name Sex Age 0 Braund, Mr. Owen Harris male 22.0 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 2 Heikkinen, Miss. Laina female 26.0 3 Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0 4 Allen, Mr. William Henry male 35.0 886 Montvila, Rev. Juozas male 27.0 887 Graham, Miss. Margaret Edith female 888 Johnston, Miss. Catherine Helen "Carrie" female 19.0 NaN 889 Behr, Mr. Karl Howell Dooley, Mr. Patrick male 890 male 26.0 32.0 [891 rows х 3 columns] In [26]: dataset2 = titanic[["Name", "Pciass", "Cabin"]] dataset2 Out [26] : Name Pclass Cabin 0 Braund, Mr. Owen Harris 3 NaN 1 Cumings, Mrs. John Bradley (Florence Briggs Th... 1 C85 2 Heikkinen, Miss. Laina 3 NaN 3 Futrelle, Mrs. Jacques Heath (Lily May Peel) 1 C123 4 Allen, Mr. William Henry 3 NaN 886 Montvila, Rev. Juozas 2 NaN 887 Graham, Miss. Margaret Edith 1 B42 888 Johnston, Miss. Catherine Helen "Carrie" 3 NaN 889 Behr, Mr. Karl Howell 1 890 Dooley, Mr. Patrick 3 C148 NaN [891 rows x 3 columns] Теперь у нас есть два DataFrame, в каждом из которых есть по 891 строке и по столб­ цу с общим идентификатором Name. При выполнении объединения Pandas будет ис­ кать общий идентификатор в обоих DataFrame и соответствующим образом соеди­ нять строки. Для ЭТОЙ операции МЫ используем функцию pd.merge (). In [27]: merged_dataset = pd.merge(dataset1, dataset2, how="left", on= "Name") merged_dataset Out[27] : Name Sex Age Pclass Cabin male female 22.0 1 Braund, Mr. Owen Harris Cumings, Mrs. John Bradley (Florence Briggs Th... 3 1 NaN C85 2 Heikkinen, Miss. Laina 26.0 Futrelle, Mrs. Jacques Heath (Lily May Peel) 35.0 3 1 NaN 3 female female 4 Allen, Mr. William Henry male 35.0 3 NaN 0 38.0 C123
350 | Гпава 18 Name Sex Age Pclass Cabin 886 Montvila, Rev. Juozas male 27.0 2 NaN 887 Graham, Miss. Margaret Edith female 19.0 1 B42 888 Johnston, Miss. Catherine Helen "Carrie" female NaN 3 NaN 889 Behr, Mr. Karl Howell male 26.0 1 C148 890 Dooley, Mr. Patrick male 32.0 3 NaN [891 rows х 5 columns] Вы видите, что набор merged dataset тоже содержит 891 строку, но уже 5 столбцов (34-3 — 1, общий столбец). У обеих таблиц общий столбец Name, который используется в качестве ключа для объединения информации. При выборе левого соединения в результирующую таб­ лицу попадают только имена, доступные в таблице dataseti (слева). В конце кон­ цов, в обоих наборах данных будут присутствовать одни и те же имена, но эта функция будет полезна, если вы будете выполнять соединение некоторых реальных данных и вам нужно будет решить, какая таблица будет первой с точки зрения выбора общего идентификатора. 18.8. Резюме Чтобы создать новый столбец, можно просто присвоить DataFrame с новой меткой столбца в [] новое значения. Операция выполняется поэлементно, и нет необходи­ мости перебирать строки. Метод rename о с переданным ему словарем или функци­ ей позволяет переименовывать метки строк или столбцов. Сводную статистику можно посчитать по целым столбцам или строкам. Метод groupbyO помогает рабо­ тать с данными по шаблону «разделение-применение-объединение». Сортировка по одному или нескольким столбцам выполняется методом sort values (). Несколько таблиц можно объединить по строкам с помощью функции concat (). Для объедине­ ния таблиц способом, аналогичным базам данных, используется функция merge ().
19 Визуализация в Python 19.1. Визуализация данных «Один рисунок стоит тысячи слов» (Роберт Дж. Барнард). Эта фраза как нельзя лучше говорит о важности визуализации для специалиста по данным или любого, кто работает с данными. Набор данных, маленький или боль­ шой, будучи представленным в виде изображения, графика или диаграммы, поз­ воляет намного больше понять специалисту по анализу и другим людям. Визуа­ лизация данных играет важную роль в представлении как малых, так и больших объемов данных. 19.1.1. Важность визуализации данных Один из ключевых навыков специалиста по данным— это умение убедительно рассказать историю. Сперва для написания этой истории нужно изучить данные, поэтому аналитик визуализирует данные во многих формах, пока необработанные данные не начнут обретать какой-то смысл. Паттерны в данных лучше видны именно при визуализации. Следовательно, изучение программных инструментов для визуализации данных позволяет вам извлекать информацию, лучше понимать данные и принимать более эффективные решения. В Python имеется богатый набор инструментов для задач визуализации данных всех видов и мастей. Существует множество библиотек, которые позволяют создавать всевозможные изображения и диаграммы. В этой главе мы рассмотрим некоторые наиболее важные инструменты, но сперва поговорим об основах визуализации дан­ ных. 19.1.2. Основы визуализации В этой главе мы будем использовать данные о загрязнении воздуха NO2, предос­ тавленные сообществом OpenAQ и полученные с помощью пакета py-openaq. Набор данных air_quality_no2.csv содержит данные о содержании NO2 с измерительных станций FR04014, BETR801 и London Westminster, которые находятся соответст­ венно в Париже, Антверпене и Лондоне. Этот набор данных наиболее часто используется при обучении основам обработки данных и науки о данных. Скачать его можно по ссылке:
352 Гпава 19 | https://github.com/nilabhnishchhal/Python-Made-Easy/blob/master/ air_quality_no2.csv Это ссылка на репозиторий GitHub. Открыв ссылку, щелкните по Raw правой кнопкой мыши и выберите команду Save link as. Сохраните файл в вашей рабочей папке и измените расширение файла на csv. Теперь в рабочей папке на вашем компьютере вы можете найти набор данных air quality nol.csv. Приступим к работе. Давайте сначала прочитаем данные с помощью Pandas, а затем воспользуемся Matplotlib для создания графиков. Вначале импортируем все зависимости. In [1]: import pandas as pd import matplotlib.pyplot as pit %matplotlib inline Примечание tonatpiotiib — это волшебная команда, которая указывает Jupyter Notebook отображать графики и изображения в самом документе. In [2]: air_quality = pd.read_csv("air_quality_no2.csv", index_col=0, parse_dates=True) In [3]: air_quality.head() Out[3]: station_antwerp station_paris station_london datetime 2019-05-07 02:00:00 NaN NaN 23.0 19.0 2019-05-07 03:00:00 50.5 25.0 2019-05-07 04:00:00 45.0 27.7 19.0 2019-05-07 05:00:00 NaN 50.4 16.0 2019-05-07 06:00:00 NaN 61.9 NaN Примечание Параметры index_coi и parse_dates функции read_csv() используются для определения первого (нулевого) столбца как индекса результирующего DataFrame и преобразования дат в столбце в объекты Timestamp соответственно. 19.1.3. Простой линейный график в Pandas Создавать графики с помощью Matplotlib и Pandas очень просто. Это делается с по­ мощью одного простого метода, название которого говорит само за себя. Метод plot () создает Графики ИЗ DataFrame (рис. 19.1), а также ИЗ объектов Графики также сами по себе являются объектами1. Series. 1 Pandas documentation, 2020 (https://pandas.pydata.Org/pandas-docs/version/l.0.4/getting_started/intro_tutorials/ index.html) [41].
Визуализация в Python | 353 Рис. 19.1. Графики в Pandas Чтобы быстро проанализировать данные, можно их построить и изучить. In [4]: air_quality.plot() 0ut[4]: <matplotlib.axes._subplots.AxesSubplot at 0x24f066ced08> 100 ------ station_antwerp ------ station paris ------ stationjondon 80 60 40 20 0 ,ЛЪ .Sp aX>b TP’V9 cJp a.Ofe a.ofe datetime Рис. 19.2. Графики качества воздуха Сейчас мы никак не настраивали оси, метки или какие-либо цвета. В результате получился простейший график, который дает нам представление об уровнях NO2 по каждому городу по датам (рис. 19.2). С помощью DataFrame по умолчанию создается линейный график для каждого столбца с числовыми данными. Допустим, мы хотим увидеть уровни NO2 только в одном городе, скажем, в Лондо­ не. Как мы уже знаем, в Pandas нетрудно выделить столбец как объект Series. Давайте сделаем это, и, как я уже сказал, у Series и DataFrame есть метод plot о. Итак, давайте посмотрим, как график строится для одного столбца (рис. 19.3). In [5]: air_quality["station_london").plot() Out[5]: <matplotlib.axes._subplots.AxesSubplot at 0x24f0a5df908> Здесь на выводе будет график из рис. 19.3. Чтобы построить определенный столбец, можно выбрать подмножество данных Series и использовать метод plot (). Следовательно, метод plot о работает как С Series, так И С DataFrame.
354 | Гпава 19 Рис. 19.3. Линейный график в Pandas 19.1.4. Базовая диаграмма рассеяния Мы визуализировали данные, представленные в столбцах, в виде временного гра­ фика. Теперь мы хотим сравнить два столбца и посмотреть, как они соотносятся друг с другом. Это можно сделать, построив их на разных осях. Давайте построим диаграмму рассеяния по Лондону и Парижу (рис. 19.4). In [6]: air_quality.plot.scatter(x="station_london", y="station_paris") Out[6J: <matplotlib.axes._subplots.AxesSubplot at 0x24f0a31c308> stationjondon Рис. 19.4. Диаграмма рассеяния в Pandas Это базовая диаграмма рассеяния. Мы можем изменить многие параметры с помо­ щью аргументов и именованных аргументов метода plot (). Позже мы рассмотрим их все, а пока я покажу вам один из них. Точки диаграммы рассеяния можно сде­ лать более прозрачными, и таким образом будет легко определить, какие области диаграммы более густо заполнены (рис. 19.5).
Визуализация в Python In [7]: air_quality.plot.scatter(x="station_london", y="station_paris", 0ut[7]: <matplotlib.axes._subplots.AxesSubplot at 0x24f0a6c2508> | 355 alpha=0.5) Рис. 19.5. Диаграмма рассеяния с эффектом прозрачности Значение прозрачности alpha может варьироваться от 0 до I. Попробуйте изменить это значение в приведенном коде и посмотрите, как будет выглядеть диаграмма при разных значениях alpha. 19.1.5. Другие виды графиков Помимо линейного графика по умолчанию, методом plot о можно строить и другие виды графиков. Давайте воспользуемся стандартными методами Python, чтобы вы­ вести список всех доступных методов построения графиков: In [8]: dir(air quality.plot) Out[8] : ['__ annotations__ ', '_call_', 1__ class__ 1, '__ delattr__ 1, '__diet__ 1, '_dir_', 1__doc__ ', '__ eq__ ', '__ format__ ', '__ ge__ 1, '__ getattribute__ 1, '_gt_', '__hash__ ', '__ init__ ', '__init_subclass __ 1 '_le__', lt_', '__module__ ', '__ ne__ ',
356 | Гпава 19 '__ new__ ', '__ reduce__ ', '__ reduce_ex__ ', '__ repr__ ', '__ setattr__ ', '__ sizeof__ ', '__ str__ ', '__ subclasshook__ ', 1__ weakref__ ', '_accessors', '_all_kinds', '_common_kinds', '-Constructor', '_dataframe_kinds', '-deprecations', '_dir_additions', '_dir_deletions', '_ensure_type', '_get_call_args', '_kind_aliases', '_reset_cache', '_serieS—kinds', 'area', 'bar', 'barh', 'box', 'density', 'hexbin', 'hist', 'kde', 'line', 'pie', 'scatter'] Давайте удалим из созданного функцией dir () списка все элементы, которые начи­ наются с символа подчеркивания _. В результате мы получим список всех методов, с помощью которых можно строить графики. Для этого я использую списковое включение. In [9]: [method_name for method_name in dir(air_quality.plot) Out[9]: ['area', if not method_name.startswith()] 'bar', 'barh', 'box', 'density', 'hexbin', 'hist',
Визуализация в Python | 357 1kde', 1 line', 'pie', 'scatter'] Примечание Во многих средах разработки (текстовые редакторы и IDE), а также в IPython и Jupyter Notebook для просмотра доступных методов можно использовать клавишу <ТаЬ>. На­ пример, введите air quality.plot и нажмите клавишу <ТаЬ> (рис. 19.6). в ш [ ]: air_quality.plot._________ area bar Jbarh |j box density Ц hexbin J hist kde line pie ’ Рис. 19.6. Вывод списка всех возможных графиков с помощью клавиши <ТаЬ> 19.1.6 . Диаграмма размаха Один из вариантов базовых диаграмм — это метод plot.box(), который строит диа­ грамму размаха. Проверим на данных о качестве воздуха (рис. 19.7). In [10]: air_quality.plot.box() Out[10]: <matplotlib.axes._subplots.AxesSubplot at 0x24f0a738fc8> Рис. 19.7. Диаграмма размаха в Pandas
358 | Гпава 19 19.1.7 . Несколько графиков На одной плоскости можно строить несколько графиков. Давайте разделим линей­ ные графики, которые мы видели выше (рис. 19.2), на несколько — по одному столбцу на каждый график (рис. 19.8). In [11]: air_quality.plot(figsize = (12,4), subplots = True) Outfll]: array([cmatplotlib.axes._subplots.AxesSubplot object at 0x0000024F0A7C3F08>, <matplotlib.axes._subplots.AxesSubplot object at 0x0000024F0A7FF248>, <matplotlib.axes._subplots.AxesSubplot object at 0x0000024F0A7DlE08>] , dtype=object) datetime Рис. 19.8. Разделение графиков в Pandas Если вам не нужен служебный текст, который выводится над графиками (array ([<matplotlib.axes. ..), самый простой способ убрать его— присвоить график другому объекту. In [12]: subplots = air_quality.plot(figsize = (12,4), subplots = True) Здесь на выводе будет та же картинка, что и на рис. 19.8, но без служебной информации перед рисунком. 19.1.8 . Сохранение графика Если вы хотите дополнительно настроить, добавить новые данные или сохранить полученный график — это тоже можно сделать. Давайте посмотрим, как выполнить простую настройку и сохранить график в виде файла PDF. In [13]: # создаем пустой рисунок matplotlib и график fig, axs = pit.subplots(figsize=(12, 4)) # используем pandas, чтобы поместить график на плоскость air_quality.plot.area(ax=axs) # настройки осей на свой вкус axs.set—ylabel("N0$_2$ concentration") # сохраняем график методами matplotlib fig.savefig("no2_concentrations.pdf")
Визуализация в Python | 359 После этого в вашей рабочей папке появится файл no2_concentrations.pdf, в кото­ ром вы найдете приведенное выше изображение (рис. 19.9). Любой график, создаваемый Pandas, является объектом Matplotlib. В Matplotlib есть множество опций для настройки графиков, а прямая связь между Pandas и Matplotlib позволяет использовать всю мощь Matplotlib для построения разнообраз­ ных видуализаций. 19.2. Библиотеки для визуализации данных Вы наверняка уже поняли, что именно совместно разрабатываемые и поддержи­ ваемые библиотеки и модули делают Python таким мощным. В этом и заключается настоящая сила Python как языка программирования и его преимущество перед другими языками. В задачах визуализации данных ситуация ничем не отличается. Есть много библиотек, которые построены на Python, таких как NumPy, Pandas и Matplotlib, крупнейшей библиотеке для визуализации данных. У каждой библиоте­ ки, которую мы обсудим далее, есть свои уникальные особенности. Мы приведем только их краткий обзор, а в следующих двух главах подробнее остановимся на визуализации в Pandas и Matplotlib. Чтобы детально изучить все остальные библио­ теки или даже Matplotlib, потребуется отдельная книга. 19.2.1. Matplotlib matplotlib Matplotlib — это самая простая библиотека для графической визуализации данных в Python. В ней вы можете найти почти все виды графиков, которые только можно при­ думать. Это базовая библиотека, но это не значит, что в ней мало возможностей. Многие библиотеки визуализации данных, о которых мы еще поговорим, основаны на ней. Matplotlib — это самая главная библиотека визуализации данных Python. Несмотря на то что ей более 10 лет, это все еще самая широко используемая сообществом
360 | Глава 19 Python библиотека для построения графиков. Она разрабатывалась так, чтобы по­ ходить на MATLAB — проприетарный язык программирования, разработанный в 1980-х гг. Поскольку Matplotlib была первой библиотекой визуализации данных Python, мно­ гие другие библиотеки построены на ее основе или работают в тандеме с ней. Не­ которые библиотеки, такие как Pandas и Seaborn, являются «обертками» над Matplotlib. В них можно вызывать некоторые методы Matplotlib, но с меньшим ко­ личеством кода. Графики в Matplotlib состоят из двух основных компонентов: axes (график, ограни­ ченный осями) и figure (рисунок, на котором мы рисуем оси, заголовки и объекты, выходящие за пределы области графика). Мы уже видели примеры использования Matplotlib и ее совместную работу с Pandas, а подробнее о Matplotlib еще погово­ рим в следующей главе. 19.2.2. Seaborn' Если вы работаете со статистическими дан­ ными и вам требуется их визуализация, то Seaborn — ваш выбор. ©seaborn Seaborn — это библиотека визуализации дан­ ных Python, основанная на Matplotlib. В ней создан высокоуровневый интерфейс для создания красивых и вместе с тем информативных статистических графиков. Seaborn построена поверх Matplotlib и тесно интегрирована со структурами данных Pandas. Приведу лишь некоторые из возможностей Seaborn: ♦ API, ориентированный на работу с наборами данных и на изучение взаимосвязей между несколькими переменными; ♦ специализированная поддержка категориальных переменных для вывода на­ блюдений или агрегированной статистики; ♦ возможности визуализации одномерных и двумерных распределений и их срав­ нение для разных подмножеств данных; ♦ автоматическая оценка и построение моделей линейной регрессии для различ­ ных типов зависимых переменных; ♦ удобный просмотр общей структуры сложных наборов данных; ♦ высокоуровневые абстракции для структурирования многослойных сеток, по­ зволяющих легко создавать сложные визуализации; ♦ лаконичный контроль над стилевым оформлением графиков в Matplotlib и не­ сколько готовых встроенных тем; ♦ инструменты для выбора цветовых палитр, позволяющие выявить закономер­ ности в данных. 1 Waskom, 2020 (https://seabom.pydata.org/introduction.html ) [49].
Визуализация в Python | 361 Seaborn стремится сделать визуализацию основным компонентом процесса иссле­ дования и анализа данных. Функции построения графиков работают с DataFrame и массивами, содержащими целые наборы данных. Под капотом у этой библиотеки выполняются необходимое семантическое отображение и статистическая агрегация для создания информативных графиков. Прежде чем перейти к другим библиотекам, давайте рассмотрим пример графика в Seaborn. В примере загружен набор данных tips — внутренний набор данных Seaborn. Вы можете запустить код на своем компьютере (рис. 19.10). In [14]: import seaborn as sns sns.setf) tips = sns.load_dataset("tips") sns.relplot(x="total_bill", y="tip", col="time", hue="smoker", style="smoker", size="size", data=tips); time = Lunch smoker • « No Yes size • • • • 0 2 4 6 total_bill Рис. 19.10. Пример графика Seaborn 19.2.3. ggplot Библиотека ggplot основана на ggplot2 (системе построения графиков языка R), а также на понятиях из базовой книги «The Grammar of Graphics», ggplot отличается от Matplotlib: он позволяет использовать слои для добавления компонент, создавая график «по кусочкам». Начинаете вы с пустых осей, затем добавляете точки, затем кривую, линию тренда и т. д. По словам создателя, ggplot не предназначен для создания гибконастраиваемой графики. Библиотека жертвует сложностью ради упрощения процесса построения графиков. ggplot тесно интегрирована с Pandas, поэтому при использовании ggplot лучше все­ го хранить данные В DataFrame.
362 | Гпава 19 19.2.4. Bokeh1 Как и ggplot, библиотека Bokeh опирается на «The Grammar of Graphics». Но, в отличие от ggplot, эта библиотека изначально работает на Python, а не перенесена из языка R. Ее сила заключается в спо­ собности создавать интерактивные веб-графики, которые можно легко выводить как объекты JSON, документы HTML или интерактивные веб-приложения. Bokeh также поддерживает потоковую передачу данных в реальном времени. bokeh Bokeh — это интерактивная библиотека визуализации, предназначенная для вывода данных в современных веб-браузерах. Ее задачи: ♦ интерактивная визуализация в современных браузерах; ♦ автономные HTML-документы и серверные приложения; ♦ выразительная и универсальная графика; ♦ работа с большими, динамическими или потоковыми данными; ♦ простое использование из Python (из Scala, R и др.). И, самое главное, для работы Bokeh не требуется JavaScript! Bokeh — это интерактивная библиотека визуализации для современных веб­ браузеров. В ней сочетается элегантное и лаконичное построение универсальной графики и высокопроизводительная интерактивность при работе с большими или потоковыми наборами данных. Bokeh подойдет любому, кто хочет быстро и легко создавать интерактивные графики, информационные панели и приложения для об­ работки данных. 19.2.5. Folium2 Библиотека Folium упрощает визуализацию данных Python на интерактивной карте. Она позволяет привязать данные к карте и выполнять визуализацию хороплетных карт. Хороплетная карта (картограмма) — это тип тематической карты, на кото­ рой области затенены или раскрашены пропорционально статистической перемен­ ной, которая представляет собой совокупную сводку географических характери­ стик в каждой области, например плотность населения или доход на душу населе­ ния. Кроме того, можно добавлять векторные/растровые/НТМЕ-изображения в качестве маркеров на карте. В этой библиотеке можно найти встроенные изображения из таких ресурсов, как OpenStreetMap, Mapbox и Stamen, а также поддерживается создание пользователь­ ских наборов с помощью Mapbox или Cloudmade API. Библиотека Folium поддер­ живает наложение изображений, видео, GeoJSON и TopoJSON. 1 Bokeh, 2019 (https://docs.bokeh.org/en/latest/ ) [5]. 2 Story, 2013 (https://python-visualization.github.io/folium/ ) [38].
Визуализация в Python | 363 Folium— это мощная библиотека Python, которая помогает создавать несколько типов карт Leaflet. С помощью Folium можно генерировать интерактивные объек­ ты, что делает эту библиотеку очень полезной для создания информационных па­ нелей. Чтобы стало понятнее, постройте карту из примера ниже (рис. 19.11) и по­ пробуйте покрутить ее или поменять масштаб. На странице GitHub проекта Folium можно найти множество других примеров. In [15]: import folium m = folium.Map(location=[45.5236, -122.6750]) In [16]: m Out[16]:<folium.folium.Map at 0x24f0ce58948> Рис. 19.11. Построение карт в Folium 19.2.6. Gleam Библиотека Gleam позволяет создавать интерактивные веб-визуализации данных с помощью Python, при этом знание HTML или JavaScript не требуется! Вы можете задать входные данные, которыми могут управлять ваши пользователи, а затем исTttto of plot Му Groat Ио» Yel» Beef «3 Smoothing Curve Рис. 19.12. Пример построения графиков в Gleam
364 | Гпава 19 пользовать любую библиотеку Python для работы с графиками, чтобы построить визуализацию данных. Gleam объединяет все это вместе и создает веб-интерфейс, который позволяет пользователю работать с данными в режиме реального времени (рис. 19.12). С этой библиотекой понимать и интерпретировать данные стало про­ ще, чем когда-либо. Идея Gleam была вдохновлена пакетом Shiny из языка R1. 19.3. Резюме Визуализация — неотъемлемая и важная часть аналитики данных. Любой специа­ лист в области Data Science должен хорошо разбираться в концепциях визуализа­ ции, а также знать библиотеки, используемые для этой цели. В этой главе мы рас­ смотрели основные диаграммы, которые можно строить с помощью Pandas и его простого, но эффективного метода plot о. Методы plot.* о можно применять как к объектам Series, так и к DataFrame. По умолчанию каждый столбец отображается как отдельный элемент (линия, график, ...). Любой график, созданный в Pandas, яв­ ляется объектом Matplotlib. Вы можете строить различные варианты графиков, спи­ сок которых можно просмотреть с помощью клавиши <ТаЬ>. Еще одним эффек­ тивным инструментом является возможность построения нескольких графиков и их сравнения на одной плоскости. В Python есть и другие библиотеки, предназначен­ ные для визуализации данных, но главной среди них все-таки является Matplotlib, а более новые библиотеки лучше работают на своих специализированных задачах. 1 Robinson, 2014 (https://github.com/dgrtwo/gleam) [33].
20 Визуализация с помощью Matplotlib Pyplot В этой и следующей главах мы рассмотрим, как можно использовать библиотеку Matplotlib для создания различных диаграмм, графиков и даже изображений в Python. Лучший способ начать изучение основ визуализации в Python — это до­ кументация и руководства по Matplotlib. В них сперва рассматриваются базовые понятия, а затем более продвинутые вещи. Эта и следующая главы, посвященные визуализации, в значительной степени опираются на документацию по Matplotlib, и я хотел бы поблагодарить команду разработчиков за великолепный обучающий ресурс, который они создали для своих пользователей1. Прежде чем мы перейдем к подробностям работы с Matplotlib, давайте разберемся с происхождением Matplotlib и самой идеей, лежащей в основе этой библиотеки. 20.1. Введение и историческая справка2 Библиотека Matplotlib изначально была написана Джоном Д. Хантером (1968— 2012), и с тех пор у нее появилось активное сообщество разработчиков. Распро­ страняется она под лицензией BSD. Примечание Приведенный ниже текст был написан в 2008 г. Джоном Д. Хантером, первоначальным автором Matplotlib. Matplotlib — это библиотека для создания 2В-графиков из массивов в Python. Из­ начально она повторяла графические команды MATLAB, но при этом совсем не зависит от MATLAB и может работать с объектами в стиле Python. Хотя Matplotlib написана в основном на чистом Python, в ней также активно используется NumPy и другие библиотеки, обеспечивающие хорошую производительность для больших массивов. Matplotlib разрабатывалась так, чтобы дать пользователю возможность создавать простые графики с помощью всего пары команд! Если вы хотите построить по 1 Matplotlib, 2020 (https://matplotlib.Org/3.2.2/tutorials/introductory/pyplot.html ) [15]. 2 Matplotlib, Histoiy, 2020 (https://matplotlib.Org/3.2.2/users/history.html) [13].
366 | Гпава 20 своим данным гистограмму, вам не нужно создавать экземпляры объектов, вызы­ вать методы, устанавливать свойства и т. д., т. к. все работает по умолчанию. Код Matplotlib концептуально разделен на три части. ♦ Интерфейс pyiab — это набор функций, предоставляемых пакетом matplotlib. который позволяет пользователю создавать графики с помощью кода, по­ хожего на код генерации графиков в MATLAB. pylab, ♦ Интерфейс Matplotlib или Matplotlib API— это набор классов, которые выполняют всю тяжелую работу, создают и управляют рисунками, текстами, линиями, графиками и т. д. Это абстрактный интерфейс, который ничего не зна­ ет о том, что он производит. ♦ Бэкенды— это зависящие от используемого устройства средства рисования, также известные как средства визуализации. С их помощью выполняется пре­ вращение внешнего интерфейса в готовые для вывода объекты. Оригинальный логотип Matplotlib (2003-2008) показан на рис. 20.1. Еще один логотип Matplotlib (2008-2015) — рис. 20.2. Рис. 20.1. Оригинальный логотип Matplotlib Рис. 20.2. Логотип Matplotlib (2008-2015) 20.2. Основные объкты Matplotlib В этой главе приведено более подробное руководство по использованию Matplotlib. Мы начнем с самых основ. Matplotlib отображает графики с помощью объектов Figure (например, в окнах, виджетах Jupyter и т. д.), каждый из которых может содержать один или несколько объектов Axes (т. е. линии с координатами х и у, а также это может быть угол-радиус в полярном графике или х, у и z в трехмерном графике). Самый простой способ соз­ дать график с осями (рис. 20.3)— использовать метод pypiot.subplots(). Затем мы можем вызвать метод Axes.plot () для отображения данных по осям. In [1]: import matplotlib.pypiot as pit import numpy as np In [2]: fig, ax = pit.subplots()
Визуализация с помощью Matplotlib Pyplot | 367 1.0 0.8 0.6 0.4 0.2 0.0 0.0 1.0 Рис. 20.3. Объект Matplotlib Figure с одиночными осями Приведенная выше строка кода создает два объекта и назначает их переменным fig (рис. 20.4) и ах соответственно. Давайте посмотрим подробнее, что это за объекты. In [3]: fig Out[3] : Здесь на выводе будет та же картинка, что и на рис. 20.3. In [4]: |out[4]: ах <matplotlib.axes.subplots.AxesSubplot at 0xlab25c03708> Итак, мы создали «график». Как видите, это просто чистый холст, на котором мож­ но рисовать график. Итак, приступим к рисованию. Второй объект — объект Axes, на котором будет построен график (рис. 20.4). In [5]: fig, ах = pit.subplots() ax.plot([l, 2, 3, 4], 0ut[5]: [1, 4, 2, 3]) # добавление данных на оси [Cmatplotlib.lines.Line2D at 0xlab27a5d248>] Рис. 20.4. Линейный график на объекте Axes
368 | Гпава 20 Многие другие библиотеки или языки построения графиков не требуют явного соз­ дания осей. В Matplotlib этого тоже можно не делать, т. к. для каждого метода построения гра­ фика Axes существует соответствующая функция в модуле matplotlib.pyplot, которая строит график на «текущих» осях, создавая сами оси по умолчанию, если их еще не создали. Таким образом, предыдущий пример можно было записать короче, а ре­ зультат был бы тем же самым (см. рис. 20.4). [1, 4, 2, 3]) In [6]: plt.plot([l, 2, 3, 4], Out[6]: [<matplotlib.lines.Line2D at 0xlab27de7f48>] Здесь на выводе будет абсолютно та же картинка, что и на рис. 20.4, только полученная с использованием метода pit.plot о. 20.2.1. Иерархия объектов Matplotlib Очень важной концепцией для работы с Matplotlib является ее иерархия объектов. Самым внешним контейнером для графики Matplotlib является объект Figure, кото­ рый может содержать несколько объектов Axes. Название Axes может немного сбить с толку новичков, т. к. это не ось в явном виде, а отдельный график. Это не множе­ ственное число от axis (ось), как может показаться. Объект Figure можно представить как контейнер, содержащий один или несколько графиков (Axes). Затем идут более мелкие объекты, которые находятся в иерархии ниже графика, такие как отметки, линии, легенды и текстовые поля (рис. 20.5). Почти каждый элемент графика — это отдельный объект Python, которым можно управлять1. __ Figure Axes -------------- Рис. 20.5. Иерархия объектов Matplotlib 1 Solomon, 2020 (https://realpython.com/python-matplotlib-guide/ ) [35].
Визуализация с помощью Matplotlib Pyplot | 369 20.2.2. Типы входных данных для графиков Все функции построения графиков ожидают на вход данные типа numpy.array или numpy.ma.masked array. Классы, которые похожи на массивы, такие как объекты дан­ ных Pandas и numpy.matrix, не всегда работают правильно или не работают вовсе. Лучше всего перед построением преобразовать данные в объекты numpy.array. Для примера преобразуем Pandas DataFrame в массив: а = pandas.DataFrame(пр.random.rand(4,5), columns = list(1abcde')) a_asarray = a.values ИЛИ В numpy.matrix: b = np.matrix([[1, 2], [3, 4]]) b_asarray = np.asarray(b) 20.3. Элементы рисунка Теперь давайте более подробно рассмотрим компоненты рисунка Matplotlib (рис. 20.6)1. 1 Matplotlib, Usage Guide, 2020 (https://matplotlib.Org/3.2.l/tutorials/introductory/usage.html) [17].
370 | Гпава 20 20.3.1. Рисунок (Figure) Это буквально все поле рисунка. На нем находятся все дочерние графики (Axes), разные элементы рисунка (названия, легенды фигур и т. д.) и холст (о холсте нам думать особо не надо, поскольку этот объект создается тихо и невидимо для поль­ зователя). Рисунок может содержать любое количество графиков, но обычно не менее одного. Самый простой способ создать новый рисунок— использовать методы (рис. 20.7 и 20.8): In [7]: fig = pit.figured # пустой рисунок без графиков fig, ах = pit.subplots() # рисунок с одним графиком fig, axs = pit.subplots(2, 2) # рисунок с сеткой графиков 2x2 pypiot <Figure size 432x288 with 0 Axes> 1.0-i------------------------------------------------------------------------------------------------------- 0.8- 0.6- 0.4- 0.2- 0.0 -I-------------------- T------------------- T--------------------1-------------------- 1-------------------0.0 0.2 0.4 0.6 0.8 1.0 Рис. 20.7. Пустой рисунок 1.00 1.00 0.75 0.75- 0.50 0.50- 0.25- 0.25- 0.00-1---------»-------- 1------ 1----------- i-------1.0 0.0 0.2 0.4 0.6 0.8 1.0 1.00-r 0.000 1.00-r 0.75- 0.75- 0.50- 0.50- 0.25- 0.25 - 0.00 - ■ 0.0 0.2 0.4 0.6 0.8 0.00 ■ ■ 1.0 0.0 0.2 0.4 0.6 0.8 1.0 Рис. 20.8. Рисунок с 4 графиками в сетке 2x2 Графики удобно создавать одновременно с рисунком, но вы также можете добавить их позже, что позволяет создавать более сложные визуализации.
Визуализация с помощью Matplotlib Pyplot | 371 20.3.2. Г рафики (Axes) Графиком мы обычно называем область изображения с данных. Рисунок может со­ держать много графиков, но каждый график может находиться только на одном рисунке. График содержит два (или три в случае трехмерного графика) объекта Axis (а вот это уже координатная ось), которые отвечают за ограничение диапазонов данных (их также можно контролировать с помощью методов axes.Axes.set_xlim() и axes.Axes.set_ylim()). У каждого графика Axes есть заголовок title (устанавливается методом set title ()), метка оси х (устанавливается методом set_xlabel()) и метка оси у (устанавливается методом set_ylabel()). Класс Axes и его методы являются основной точкой входа объектно-ориентиро­ ванного интерфейса. 20.3.3. Оси (Axis) Это объекты, похожие на числовые линии. Они отвечают за ограничение пределов графика, генерацию делений на осях (tick) и подписей к делениям (ticklabel). Распо­ ложение делений определяется объектом Locator, а подписи формируются с по­ мощью Formatter. Правильное сочетание Locator и Formatter позволяет получить очень точный контроль над расположением делений и меток. 20.3.4. Объекты Artist В основном все, что вы видите на рисунке, является объектами Artist (даже объек­ ты Figure, Axes и Axis). Объектами Artist также являются объекты Text, объекты Line2D, объекты коллекций, объекты Patch и т. д. В момент отображения рисунка все эти объекты выводятся на холст. Большинство Artist привязаны к конкретному графику Axes, и тогда они не могут использоваться другими графиками или переда­ ваться от одного графика к другому. 20.4. Два способа использования Matplotlib В целом можно выделить два способа построения графиков с помощью Matplotlib: ♦ объектно-ориентированный интерфейс (ОО API); ♦ интерфейс Pyplot (Pyplot API). 20.4.1 . Объектно-ориентированный интерфейс При использовании этого способа Matplotlib вы будете явно создавать объекты рисунков и графиков и вызывать их методы (так называемый объектно-ориенти­ рованный стиль). Пример кода с использованием этого интерфейса (рис. 20.9): In [8]: х = np.linspace (0, 2, 100) # создание входных данных в виде # массива numpy для построения графика
372 | Глава 20 # обратите внимание, что даже в объектно-ориентированном стиле # для создания рисунка используется pyplot fig, ах = pit.subplots() # создание рисунка и графика ах.plot(х, х, label="linear") # вывод данных на график ах.plot(х, х**2, label="quardratic") # еще одна кривая Out[8]: ах.plot(х, х**3, label="cubic") # и еще одна ах.set_xlabel('х label') # добавление метки оси х ах.set_ylabel('у label') # добавление метки оси у ах.set_title("Simple Plot") # добавление заголовка ах.legend() # добавление легенды cmatplotlib.legend.Legend at 0xlab275ef3c8> Рис. 20.9. График, построенный с помощью объектно-ориентированного интерфейса 20.4.2 . Интерфейс Pyplot В этом конкретном интерфейсе вместо того, чтобы создавать рисунки и графики вручную, мы используем функции модуля pyplot, который автоматически создает нужные объекты и управляет ими. Этот же модуль мы будем использовать для по­ строения графиков. Тот же пример, который мы видели ранее (рис. 20.9), но с использованием интер­ фейса Pyplot для построения: In [9]: х = np.linspace(0, 2, 100) pit.plot(х, х, label = "linear") # вывод данных на график pit.plot (х, х**2, label = "quardratic") # еще одна кривая pit.plot(х, х**3, label = "cubic") # и еще одна plt.xlabelf'x label') # добавление метки оси х pit.ylabel('у label') # добавление метки оси у pit.title("Simple Plot") # добавление заголовка pit.legend!) # добавление легенды
Визуализация с помощью Matplotlib Pypiot | Out[9]: 373 <matplotlib.legend.Legend at 0xlab27a5dac8> Здесь на выводе будет абсолютно тот же график, что и на рис. 20.9, но построенный с помощью функций pypiot. 20.4.3 . Так какой же способ лучше? В документации и примерах Matplotlib используется как объектно-ориентиро­ ванный подход, так и модуль pypiot. Оба варианта одинаково сильны, и вы можете применять любой из них. Но вот использовать их одновременно не рекомендуется, и я советую вам выбрать один стиль и придерживаться его. При смешивании под­ ходов растет вероятность ошибок. Ваш выбор также может зависеть от того, для чего вы чаще используете Matplotlib. Мои рекомендации таковы: ♦ если вам больше нравится интерактивное построение графиков (например, в Jupyter Notebook) или, другими словами, если вы создаете графики для презен­ тации, предпочтительнее использовать интерфейс Pypiot; ♦ если вам больше нравится неинтерактивное построение графиков (в функциях и скриптах, которые должны многократно использоваться в рамках более крупно­ го проекта), предпочтительнее объектно-ориентированный стиль. 20.5. Построение схожих графиков с помощью функций Обычно возникает необходимость многократно строить схожие графики, но с раз­ ными наборами данных, и в этом случае возникает необходимость написать специ­ альные функции для построения графиков. Рекомендуемая сигнатура функции вы­ глядит примерно так: In [10]: def my_plotter(ах, datal, data2, param_dict): """ Вспомогательная функция для построения графика Параметры ах: Axes Отображаемые графики datal: array Данные х data2: array Данные у param_dict: diet Словарь kwargs для передачи в ах.plot() Возвращаемое значение out: list Список добавленных элементов I» IIII out = ах.plot(datal, data2, **param_dict) return out
374 Глава 20 | Эту функцию можно использовать в следующих примерах. Допустим, код для рис. 20.10: In [11]: %matplotlib inline In [12]: datal, data2, data3, data4 = np.random.randn (4, 100) fig, ax = pit.subplots(1, 1) my_plotter(ax, datal, data2, Out[12]: {'marker': 'x'}) [<matplotlib.lines.Line2D at 0xlab280feac8>] Данную функцию можно применить и для рисования, например, двух графиков на одном рисунке (рис. 20.11). In [13]: fig, (axl, ах2) = pit.subplots(1, 2) myjalotter(axl, datal, data2, {'marker': 'x'}) myjplotter(ax2, data3, data4, {'marker': 'o'}) Out[13]: [Cmatplotlib.lines.Line2D at 0xlab281c5588>] Рис. 20.11. Вывод двух графиков на одном рисунке с помощью функции my_plotter ()
Визуализация с помощью Matplotlib Руplot | 375 Поскольку мы рассматриваем очень простые примеры, вам может показаться, что такой «функциональный» подход является излишним. Но это просто примеры для объяснения такого подхода. Как только ваши графики начнут немного усложнять­ ся, усилия, потраченные на написание отдельных функций, начнут многократно окупаться. 20.6. Модуль Pyplot1 Модуль matplotlib.pyplot представляет собой набор функций, которые заставляют Matplotlib работать как MATLAB. Каждая функция pyplot каким-то образом рабо­ тает с рисунком, например создает рисунок, создает график, строит линии на гра­ фике, добавляет метки на график и т. д. В matplotlib.pyplot при вызовах разных функций состояния сохраняются, поэтому модуль всегда работает текущим рисунком, а функции всегда строят на текущем графике. Примечание Интерфейс Pyplot обычно менее гибкий, чем объектно-ориентированный API. Боль­ шинство вызовов функций, которые мы рассматриваем здесь, также могут быть заме­ нены на методы объекта Axes. Создание визуализаций с помощью In [14]: pyplot выполняется очень быстро (рис. 20.12). import matplotlib.pyplot as pit pit.plot] [1, 2, 3, 4]) pit.ylabel('some numbers') pit.show() Рис. 20.12. Простой линейный график с помощью pyplot 1 Matplotlib, 2020 (https://matplotlib.Org/3.2.2/tutorials/introductory/pyplot.html ) [15].
376 | Гпава 20 Вам может быть интересно, почему ось х находится в диапазоне от 0 до 3, а ось у — от 1 до 4. Если вы передаете команде plot о один список или массив, Matplotlib предполагает, что это последовательность значений у, и автоматически генерирует значения х. Поскольку индексы в Python начинаются с 0, а вектор х по умолчанию имеет ту же длину, что и у, но начинается с 0. Следовательно, данные по оси х имеют вид [0, 1, 2, 3]. универсальная функция, которая принимает произвольное количество аргументов. Например, чтобы построить график зависимости х от у, вы можете вы­ полнить команду (рис. 20.13): plot () — In [15]: plt.plot([l, 2, 3, 4], Out[15]: [<matplotlib.lines.Line2D at 0xlab2824b748>] [1, 4, 9, 16]) Рис. 20.13. График зависимости x от у с помощью pyplot 20.7. Функция plot() Синтаксис функции построения графиков выглядит так: matplotlib.pyplot.plot(*args, scalex=True, scaley=True, data=None, **kwargs) Посмотрим, как ее вызывать. Сигнатуры вызовов приведены ниже: plot([х], у, [fmt], *, data = None, **kwargs) или plot([x], у, [fmt], [x2], y2, [fmt2], ..., **kwargs) Координаты точек или узлы линий задаются с помощью х, у. Необязательный па­ раметр fmt позволяет удобно определить базовое форматирование, такое как цвет, маркер и стиль линий. В следующих строках кода приведены примеры вызова функции plot (). # график х и у со стилем и цветом по умолчанию »> plot (х, у) »> plot(x, у, ' Ьо') # график с маркерами в виде синих кружков
Визуализация с помощью Matplotlib Pyplot | »> plot (у) »> plot (у, 377 # построить значения у с индексами вместо х ' г+') # то же самое, но с красными плюсами 20.7.1. Построение индексированных данных Существует удобный способ построения объектов с индексированными данными (т. е. данными, к которым можно получить доступ по индексу obj [i]). Вместо того, чтобы передавать данные в параметрах х и у, вы можете передать сам объект и задать метки для осей х и у: >» plot (' xlabel', ' ylabel', data=obj) Функция поддерживает все индексируемые объекты. Это может быть, например, словарь, DataFrame ИЛИ структурированный массив numpy. 20.7.2. Построение нескольких наборов данных Существуют разные способы построить несколько наборов данных. 1. Самый простой способ — просто вызвать функцию plot () несколько раз, напри­ мер: »> plot(xl, yl, 'Ьо') »> plot(x2, у2, 'до') 2. Если ваши данные уже являются двумерным массивом, вы можете передать их напрямую в х, у. При этом для каждого столбца будет нарисован отдельный набор данных. Пример для массива а, в котором первый столбец представляет значения а другие столбцы — столбцы у: х, »> plot (а [0], а [1: ]) 3. Третий способ— указать последовательно несколько групп >» plotfxl, yl, 'дл', х2, у2, [х], у, [fmt]: 'д-') В этом случае любой дополнительный именованный аргумент применяется ко всем наборам данных. Кроме того, этот синтаксис нельзя комбинировать с параметром data. 20.7.3. Форматирование стиля Для каждой пары аргументов х, у существует необязательный третий аргумент, в который нужно передать строку формата, позволяющую задать цвет и тип линии графика. Буквы и символы строки формата взяты из MATLAB, и цвет задается вме­ сте со стилем линии. Строка формата по умолчанию ь-, что означает сплошную синюю линию. В следующем примере мы сделаем на графике два изменения (рис. 20.14): ♦ заменим сплошную синюю линию на красные круглые маркеры; ♦ зададим размер оси.
378 | In [16]: Гпава 20 plt.plot([l, 2, 3, 4], [1, 4, 9, 16], 'го') plt.axis([0, 6, 0, 20]) pit.show() Рис. 20.14. Пример изменения формата линии Функция axis () в приведенном примере принимает список указывает диапазон значений по осям. [xmin, xmax, ymin, ушах] и Если бы библиотека Matplotlib умела работать только со списками, она была бы почти бесполезна для численных вычислений. Чаще всего в таких задачах исполь­ зуются массивы NumPy. Фактически все последовательности конвертируются в массивы NumPy. В приведенном ниже примере показано построение нескольких линий с разной строкой формата с помощью одной команды и с использованием массивов (рис. 20.15). In [17]: import numpy as np # временной ряд с шагом 200 мс (0.2) t = np.arange(0., 5., 0.2) # красный пунктир, синие квадраты и зеленые треугольники plt.plot(t, t, 'г—', t, t**2, 'bs', t, t**3, 'gA') pit.show() Рис. 20.15. Пример нескольких линий с разным форматом на одном графике
Визуализация с помощью Matplotlib Pyplot | 379 Давайте теперь подробнее остановимся на параметрах функции plot () и на том, что она возвращает. 20.8. Параметры функции plot()x 20.8.1. Параметры х, у Эти параметры обозначают горизонтальные и вертикальные координаты точек данных. Если значения х не указаны, будут приняты значения по умолчанию как range (len (у)). Обычно эти параметры представляют собой одномерные массивы. Они также могут быть скалярами или двумерными массивами (в этом случае столбцы представляют отдельные наборы данных). Эти аргументы нельзя передавать как именованные. 20.8.2. Строка формата (fmt) Это необязательный аргумент типа str. Имя fmt — это сокращение от format string. Строка формата предназначена для простой настройки основных свойств линии. Этот аргумент нельзя передавать как именованный. Строка формата состоит из обозначения цвета, маркера и линии: fmt = '[маркер][линия][цвет]' Каждый из этих компонентов необязательный. Если значение не задано, использу­ ется значение из списка стилей по умолчанию. Но есть исключение: если указана линия, но нет маркера, данные будут построены без маркеров. Комбинации в дру­ гом порядке, например ' [цвет] [маркер] [линия]', также поддерживаются, но учтите, что расшифровка может дать и неоднозначный результат. 20.8.2.1. Маркеры Символ Описание Символ Описание 1 1 Точка '2' Треугольник вершиной вверх 1 1 Пиксел '3' Треугольник вершиной влево 'О' Кружок ' 4' Треугольник вершиной вправо 'v' Треугольник вершиной вниз 's' Квадрат 1 А | Треугольник вершиной вверх 'р' Пятиугольник '<' Треугольник вершиной влево I*I Звездочка *>' Треугольник вершиной вправо •h’ Шестиугольник! '1' Треугольник вершиной вниз 'Н' Шестиугольник2 ! 1 Matplotlib, 2020 (https://matplotlib.Org/3.2.2/tutorials/introductory/pyplot.html ) [15].
380 Гпава 20 | (окончание) Символ •х’ 'D' Символ Описание Описание Плюс 'd' Тонкий ромбик Крестик '/' Вертикальная черточка Ромб 1 Горизонтальная черточка 1 20.8.2.2. Стили линий Символ Описание Сплошная линия 1 _ ! • ___ ’ Пунктирная линия 1_ Штрихпунктирная линия • 1 . 1 Точечная линия 20.8.2.3. Цвета Цвета представлены в виде сокращенных однобуквенных кодов. Цвет Символ Цвет Символ ■Ь' Синий 'ш* Розовый g Зеленый 'У' Желтый ’г' Красный 'к' Черный •с' Голубой *w’ Белый Пример строк формата: 'Ь' # синие маркеры по умолчанию 'or' # красные кружки '-д' # зеленая сплошная линия '— ' # пунктирная линия с цветом по умолчанию 'Ак:' # черные треугольники вершиной вверх, соединенные точечной линией 20.8.3. Данные (data) Необязательный индексируемый объект с помеченными данными. Если этот пара­ метр указан, задаются имена меток для построения графика в координатах х и у.
Визуализация с помощью Matplotlib Pyplot | 381 20.9. Возвращаемый объект plot() Функция plot () возвращает линии. Линия содержит непосредственно кривую, соединяющую все вершины, и маркеры в каждой вершине. Кроме того, на прорисовку линии влияет стиль рисования, например можно создавать «ступенчатые» линии. 20.10. Именованные аргументы (**kwargs) Это необязательные именованные аргументы, определяющие разные свойства гра­ фиков. Они используются для определения подписей к осям (для легенды), ширины линии, сглаживания, цвета маркера. Например: »> plot([l, 2, 3], [1, 2, 3], 'go-', label='line 1', linewidth=2) »> plot([l, 2, 3], [1, 4, 9], 'rs', label='line 2') Если вы создаете несколько линий с помощью одной функции определенные в kwargs, применятся ко всем линиям. plot О, свойства, В табл. 20.1 приведен список наиболее полезных именованных аргументов функ­ ции plot(). ТАБЛИЦА 20.1 Свойство Описание alpha float ИЛИ None animated bool antialiased ИЛИ аа bool color ИЛИ с Цвет contains Вызываемый объект data (2, N) массив или два одномерных массива drawstyle ИЛИ ds ('default', 'steps', 'steps-pre', 'steps-mid', 'steps-post'), по умолчанию 'default' figure Figure fillstyle {'full', 'left', 'right', 'bottom', 'top', 'none'} gid str label object linestyle ИЛИ Is {'-', linewidth ИЛИ Iw float marker Стиль маркера markeredgecolor ИЛИ mec Цвет markeredgewidth ИЛИ mew float '', (offset, on-off-seq), ...)
382 | Гпава 20 ТАБЛИЦА 20.1 (окончание) Свойство Описание markerfacecolor или mfc Цвет markersize или ms float pickradius float url str visible bool xdata Одномерный массив ydata Одномерный массив 20.11. Построение графиков по меткам Бывают случаи, когда данные хранятся в формате, который позволяет обращаться к определенным переменным с помощью строковых меток (для столбцов или строк). Например, так можно делать в numpy. recarray или DataFrame в Pandas. Matplotlib позволяет вам передать такой объект в аргументе data. И тогда вы може­ те в качестве х и у указывать соответствующие метки (рис. 20.16). In [18]: data = {'a': np.arange(50), 'с': np.random.randint(0, 50, 50), 'd': пр.random.randn(50)} data[’b'] = data['a’] + 10 * np.random.randn (50) dataf'd'J = np.abs(data['d']) * 100 plt.scatter('a', 'b', c='c', s='d', data=data) plt.xlabelf entry a') pit.ylabel('entry b') pit.show() Рис. 20.16. Построение графика по меткам
Визуализация с помощью Matplotlib Pyplot | 383 20.12. Построение графиков с категориальными переменными Вы также можете построить график с использованием категориальных перемен­ ных. Matplotlib позволяет передавать категориальные переменные напрямую во многие функции построения графиков (рис. 20.17). In [19]: names = ['group_a', 'group_b', 'group_c'J values = [1, 10, 100] pit.figure(figsize= (9, 3)) pit.subplot(131) # первый график (в сетке 1x3, первый слева) pit.bar(names, values) plt.subplot(132) # второй график (в сетке 1x3, второй слева) pit.scatter(names, values) pit.subplot(133) # третий график (в сетке 1x3, третий слева) pit.plot(names, values) pit.suptitle('Categorical Plotting') pit.show() Рис. 20.17. Графики с категориальными переменными 20.13. Изменение свойств линии У линий есть множество атрибутов, которые вы можете задавать: ширина линии, пунктирность, сглаживание и т. д. — все они перечислены в списке аргументов (**kwargs). Существует несколько способов задать свойства линии. 1. Использовать именованные аргументы: pit.plot(х, у, linewidth = 2,0) 2. Использовать методы экземпляра Line2D. Функция plot О возвращает список объ­ ектов Line2D, например linel, line2 = plot(xl, yl, x2, y2). В следующем примере кода мы предположим, что у нас есть только одна линия, поэтому возвращаемый список имеет длину 1. С помощью распаковки кортежа получим первый эле­ мент:
384 | Гпава 20 line, = pit.plot(х, у, # отключение сглаживания line.set_antialiased(False) 3. Использовать функцию setpO. В приведенном ниже примере для установки нескольких свойств используется команда в стиле MATLAB. Функция setp() хорошо работает со списком объектов или с одним объектом. Вы можете ис­ пользовать именованные аргументы в стиле Python или пары «строка/значение» в стиле MATLAB: lines = pit.plot(xl, yl, x2, y2) # именованные аргументы pit.setp(lines, color='r', linewidth=2.0) pit.setp(lines, 'color', 'r', 'linewidth', 2.0) # «строка/значение» в стиле MATLAB 20.14. Работа с несколькими рисунками и графиками У модуля pyplot есть информация о текущем рисунке и текущем графике. Все ко­ манды построения применяются к текущему графику. Функция дса() возвращает текущий график (экземпляр matplotlib.axes.Axes), a gcf о возвращает текущий рису­ нок (экземпляр matplotlib.figure.Figure). Обычно этого делать не нужно, потому что работа с этими объектами выполняется фоном. Ниже приведен сценарий для созда­ ния двух графиков (рис. 20.18). In [20] : def f (t) : return np.exp(-t) * np.cos(2*np.pi*t) tl = np.arange(0.0, 5.0, 0.1) t2 = np.arange(0.0, 5.0, 0.02) pit.figure() pit.subplot(211) plt.plot(tl, f(tl), 'bo', t2, f(t2), 'k') pit.subplot(212) pit.plot(t2, np.cos(2*np.pi*t2), 'r—') pit.show() Рис. 20.18. Несколько графиков на одном рисунке
Визуализация с помощью Matplotlib Pypiot | 385 Команда figured здесь не является обязательной, потому что, если вы не зададите рисунок и график, по умолчанию будет создан объект figure(1) и subplot (111). Команда subplot () принимает параметры nrows, ncois (размеры сетки графиков) и index (порядковый номер графика, считая слева и с 1), где index находится в диапазоне от 1 до nrows * ncois. Запятые между параметрами можно не указывать, если все числа меньше 10. Таким образом, вызов subplot (211) идентичен subplot (2, 1, 1). Вы можете создать любое количество дополнительных графиков. Если вы хотите разместить их на рисунке вручную (например не в равномерной сетке), то можете указать расположение графиков с помощью функции axes ([left, bottom, width, height]), где все параметры указать в виде долей от размера всего рисунка (от 0 до 1). Вы можете создать несколько рисунков, выполнив несколько вызовов figured с разными числами. Каждый из созданных рисунков может содержать сколько угодно графиков (рис. 20.19 и 20.20). In [21]: plt.figure(l) # создаем рисунок! pit.subplot(211) # первый график на рисунке1 plt.plot([l, 2, 3]) pit.subplot(212) # второй график на рисунке! plt.plot([4, 5, 6]) pit.figure(2) # создаем рисунок2 plt.plot([4, 5, 6]) # создаем график (111) pit.figure(1) # текущим будет рисунок! и график (212) pit.subplot(211) # текущим делаем график (211) pit.title('Easy as 1, 2, ' ;') # вывод заголовка для графика 211 Out[21]: Text(0.5, 1.0, 'Easy as 1, 2, 3') Рис. 20.19. Графики 211 и 212 на рисунке1
386 | Гпава 20 Рис. 20.20. График 111 на рисунке2 Вы можете очистить текущий рисунок с помощью метода clf(), а текущий гра­ фик — с помощью метода cla (). Если вас раздражает то, что работа с состояниями (в частности, текущий рисунок и график) выполняется за кулисами, не отчаивай­ тесь: это всего лишь тонкая оболочка с отслеживанием состояния вокруг объектноориентированного API, которую вы можете использовать и сами. Если вы создаете много рисунков, вам нужно знать еще об одной важной вещи. Память, необходимая для рисунка, не освобождается полностью, пока рисунок не будет явно закрыт с помощью метода close(). Удаления всех ссылок на рисунок или закрытия окна, в котором рисунок выведен на экране, недостаточно, потому что pyplot хранит внутренние ссылки до тех пор, пока не будет явно вызван метод close (). 20.15. Вставка текста на график Функция text () используется для добавления текста в произвольном месте на те­ кущем графике, а функции xlabelO, ylabelO и title о используются для добавления соответствующих подписей к осям и заголовка (рис. 20.21). Все команды text о возвращают экземпляр объекта matplotlib.text.Text. Как и ра­ нее, вы можете настроить свойства текста, передав именованные аргументы в функцию text () или используя метод setp (). In [22]: mu, sigma = 100, 15 x = mu + sigma * np.random.randn(10000) # гистограмма n, bins, patches = pit.hist(x, 50, density=l, facecolor='g', alpha=0.75) pit.xlabel('Smarts', fontsize=14, color='red') pit.ylabel('Probability') plt.title('Histogram of IQ')
Визуализация с помощью Matplotlib Pyplot | plt.text(60, 387 .025, r'$\mu=100,\ \sigma=15$') pit.axis([40, 160, 0, 0.03]) pit.grid(True) pit.show() Рис. 20.21. Пример с произвольным текстом на графике 20.16. Использование математических выражений в тексте Matplotlib в любых текстовых полях принимает математические выражения, напи­ санные с помощью синтаксиса ТеХ. Например, чтобы записать в заголовке выра­ жение Oj=15, вы можете написать выражение ТеХ, окруженное знаками дол­ лара: pit.title(г'$\sigma_i=15$') Символ г перед строкой заголовка весьма важен, т. к. он означает, что строка явля­ ется необработанной строкой, и в этом случае обратная косая черта не учитывается как экранирующий символ Python. У Matplotlib есть встроенный анализатор выра­ жений ТеХ, механизм компоновки и математические шрифты. Таким образом, вы можете использовать математический текст на разных платформах, не устанавли­ вая ТеХ. Если у вас установлены LaTeX и dvipng, то для форматирования и вывода изображения на экран вы также можете использовать LaTeX. 20.16.1. Аннотирование текста Функция text () помещает текст в произвольную позицию на графике. Обычно текст используется для вывода пояснений к графику, а метод annotate () выполняет вспомогательные функции, упрощающие создание аннотаций (рис. 20.22). В анно­ тации необходимо учитывать два момента: ее расположение, представленное аргу­ ментом ху, и расположение текста xytext. Оба этих аргумента являются кортежами (X, у).
388 | In [23]: Гпава 20 ах = pit.subplot(111) t = np.arange(O.t), 5.0, 0.01) s = np.cos(2 * np.pi * t) line, = pit.plot (t, s, lw=2) pit.annotate('local max', xy=(2, 1), xytext=(3, 1.5), arrowprops=dict(facecolor='black', shrink=0.05), ) plt.ylim(-2, 2) pit.show() 2.0 local max 1.5 1.0 0.5 0.0 -0.5 -1.0 -1.5 -2.0 0 1 2 3 4 5 Рис. 20.22. Пример аннотации, добавленной на график 20.17. Логарифмические и другие нелинейные оси Matplotlib поддерживает не только линейные шкалы осей, но также логарифмиче­ ские и логит-шкалы. Такие шкалы часто используются, если данные охватывают много порядков. Изменить масштаб оси легко: plt.xscale('log') Пример четырех графиков с одинаковыми данными, но разными масштабами для оси Y приведен на рис. 20.23. In [24]: from matplotlib.ticker import NullFormatter # # полезно для логит-шкалы исправление случайного состояния для воспроизводимости пр.random.seed(19680801) # генерируем данные в интервале (0, 1) у = пр.random.normal(1ос=0.5, scale=0.4, size=1000) у = у [ (у > 0) & (у < 1) ] у. sort () х = np.arange(1еп(у))
Визуализация с помощью Matplotlib Pyplot | pit.figure() # линейный график pit.subplot(221) pit.plot(х, у) pit.yscale('linear') pit.title('linear') pit.grid(True) # логарифмическая шкала по оси Y pit.subplot(222) pit.plot(x, y) pit.yscale('log') pit.title ('log') pit.grid(True) # симметричная логарифмическая шкала по оси Y pit.subplot(223) pit.plot(х, у - y.meanO) pit.yscale('symlog', linthreshy=O.01) pit.title('symlog') pit.grid(True) # логит-шкала pit.subplot(224) pit.plot (x, y) pit.yscale('logit') pit.title('logit') plt.grid(True) # добавляем расстояние мевду графиками, чтобы метки на осях # не наезжали на соседние графики plt.subplots_adjust(top=0.99, bottom=0.05, left=0.10, right=0.99, hspace=0.50, wspace=0.65) pit.show() Рис. 20.23. Примеры нелинейных осей 389
390 | Гпава 20 20.18. Резюме Matplotlib — самая популярная библиотека визуализации, а также одна из старей­ ших библиотек во всем Python. Мы узнали, что она зародилась из MATLAB, но се­ годня ее возможности намного шире. Вы познакомились с двумя популярными подходами: Pyplot API и объектно-ориентированный API. В этой главе мы больше работали с интерфейсом Pyplot. Мы последовательно выполнили весь процесс от создания пустого рисунка до построения одного или нескольких графиков. Анато­ мия рисунка и графика весьма важна для понимания работы с библиотекой. Напи­ сание пользовательской функции для многократного построения схожих графиков может быть очень полезно при работе с данными. Кроме того, мы рассмотрели бо­ лее тонкие настройки графиков, такие как форматирование осей, меток и стилей. Построение графиков с помощью Matplotlib не всегда простая задача для новичка, но как только вы освоите основы, вам будет несложно создавать даже самые слож­ ные графики.
21 Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib В этой главе мы покажем как создавать визуализации с помощью Matplotlib от на­ чала до конца. Мы начнем с необработанных данных и закончим сохранением готового рисунка. Попутно мы постараемся выделить некоторые полезные функ­ ции и передовые методы работы с Matplotlib. Мы увидим жизненный цикл графи­ ка1, от начала (создание объекта) до конца (сохранение в файл). 21.1. Сравнение объектно-ориентированного API и Pyplot API У Matplotlib есть два подхода для работы с графиками. Первый — это использова­ ние объектно-ориентированного интерфейса (ОО API). Работая с ним, для отрисовки визуализаций на объекте рисунка figure.Figure мы используем объект графика axes. Axes. Второй подход похож на MATLAB и опирается на функции модуля pyplot (Pyplot API). Мы подробно рассмотрели интерфейс pyplot в предыдущей главе. Большинство терминов очевидны, но главное помнить, что: ♦ объект Figure — это окончательное изображение, которое может содержать в себе один или несколько графиков; ♦ объект Axes — это отдельный график, а не оси, как можно предположить из на­ звания. При объектно-ориентированном подходе мы вызываем методы объектов, которые непосредственно строят график, что дает нам гораздо больше гибкости в его на­ стройке. Примечание Вы можете попробовать использовать объектно-ориентированный интерфейс поверх интерфейса Pyplot, если хотите достичь большей гибкости и мощности в настройке графика. 1 Matplotlib, 2020 (https://matplotlib.Org/3.2.l/tutorials/introductory/lifecycle.html) [16].
392 | Глава 21 21.2. Данные для работы Для построения графика мы будем использовать словарь data, приведенный ниже. Значения и ключи этого словаря сохранены в виде двух списочных переменных. В дальнейшем именно они будут использоваться для построения графиков. In [1]: import numpy as np import matplotlib.pypiot as pit from matplotlib.ticker import FuncFormatter data = {'Barton LLC: 109438.50, 'Frami, Hills and Schmidt': 103569.59, 'Fritsch, Russel and Anderson': 112214.71, 'Jerde-Hilpert': 112591.43, 'Keeling LLC: 100934.30, 'Koepp Ltd': 103660.54, 'Kulas Inc': 137351.96, 'Trantow-Barrows': 123381.38, 'White-Trantow': 135841.99, 'Will LLC: 104437.60} group_data = list(data.values()) group_names = list(data.keys()) group_mean = np.mean(group_data) 21.3. Построение графика по умолчанию Эти данные напрашиваются на визуализацию в виде горизонтальной столбчатой диаграммы, где один столбец соответствует конкретной группе. Чтобы сделать это с помощью объектно-ориентированного подхода, мы сначала создадим экземпляр Figure и Axes (рис. 21.1). Рисунок— это словно холст, а график— это часть этого холста, на котором мы будем рисовать диаграмму. На рисунке может быть не­ сколько графиков, но мы пока ограничимся одним. In [2]: fig, ах = pit.subplots() 1.0 и----------------------------------------------------------------------------------------------------- 0.8 - 0.6 ■ 0.4- 0.2 - 0.0-1------------------- т------------------- >------------------- т------------------- т------- ----------0.0 0.2 0.4 0.6 0.8 1.0 Рис. 21.1. Создание рисунка Figure с пустым графиком
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib Теперь, когда у нас есть экземпляр (рис. 21.2). In [3]: Axes, | 393 мы можем построить на нем диаграмму fig, ах = pit.subplots() ах.barh(group_names, group_data) Out[3]: <BarContainer object of 10 artists> Рис. 21.2. Столбчатая диаграмма no умолчанию 21.4. Управление стилями В Matplotlib доступно множество стилей, позволяющих менять вид графиков по вашему желанию. Чтобы увидеть список всех стилей, используйте модуль style. In [4]: print(pit.style.available) ['bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight ', 'ggplot', 'grayscale', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark-palette', 'seaborndark ', 'seaborn-darkgrid ', 'seaborn-deep', 'seaborn-muted', 'seaborn-notebook ', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'seaborn', 'Solarize_Light2 ', 'tableaucolorblindlO', 'classic test'] В этом списке перечислены названия всех доступных стилей. Мы будем использо­ вать один из них: In [5]: pit.style.use("ggplot") Теперь давайте снова построим диаграмму, чтобы оценить изменения (рис. 21.3). In [6]: fig, ах = pit.subplots() ах.barh(group_names, group_data) Out[6]: <BarContainer object of 10 artists> Здесь на выводе будет диаграмма из рис. 21.3. Стиль задает сразу несколько параметров: цвет, ширину линий, фон и т. д.
394 | Гпава 21 Рис. 21.3. Диаграмма со стилем ggplot 21.5. Разные настройки графика Теперь у нас есть график, вид которого нас устраивает. Давайте настроим его так, чтобы его можно было напечатать. Во-первых, давайте выведем метки у оси х под углом, чтобы они отображались не так плотно (рис. 21.4). Обратиться к этим мет­ кам можно с помощью метода Axes.get_xticklabels(): labels = ax.get_xticklabels() Теперь мы собираемся установить свойство сразу для нескольких элементов. В этом нам поможет функция pypiot.setpf). Эта функция берет список (или не­ сколько списков) объектов Matplotlib и пытается установить некоторые элементы стиля для каждого из них. In [7]: fig, ах = pit.subplots () ax.barh(group_names, group_data) labels = ax.get_xticklabels() pit.setp(labels, rotation=45, horizontalalignment='right') Out[7]: [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib | 395 None, None] Рис. 21.4. Диаграмма с метками х, наклоненными под 45° Далее мы добавим на график подписи (рис. 21.5). Чтобы сделать это с помощью объектно-ориентированного интерфейса, мы можем использовать метод Axes. set (). In [8]: fig, ax = pit.subplots() ax.barh(group_names, group_data) labels = ax.get_xticklabels() plt.setp(labels, rotation=45, horizontalalignment= 'right') ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', title='Company Revenue') Out[8]: [Text(0, 0.5, 'Company'), (-10000, 140000), Text(0.5, 0, 'Total Revenue'), Text (0.5, 1.0, 'Company Revenue')] Рис. 21.5. Добавленные подписи на график
396 Гпава 21 | Мы также можем настроить размер этого графика с помощью функции subplots (). Для этого есть аргумент figsize (рис. 21.6). pyplot. Примечание При выполнении индексации NumPy следует форме (строка, столбец), а параметр figsize следует форме (ширина, высота). Такой порядок связан с соглашениями об именовании в задачах визуализации, которые, к сожалению, отличаются от таковых в линейной алгебре. In [9]: fig, ах = pit.subplots(figsize= (4, 4)) ax.barh(group_names, group_data) labels = ax.get_xticklabels() pit.setp(labels, rotation=45, horizontalalignment='right') ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', title='Company Revenue') Out[9]: [Text(0, 0.5, 'Company'), (-10000, 140000), Text(0.5, 0, 'Total Revenue'), Text(0.5, 1.0, 'Company Revenue')] Рис. 21.6. Изменение размеров графика Наши метки по оси х указаны в долларах, а цифры довольно большие. Мы можем их подредактировать или изменить форматирование, чтобы внешний вид был по­ нятнее. Для меток мы можем задать правила форматирования в виде функции с по­ мощью класса ticker.FuncFormatter. Давайте определим функцию, которая прини­ мает в качестве входных данных целое число и возвращает отформатированную строку. In [10]: def currencyfx, pos): # Два аргумента - это значение и позиция отрезка if х >= 1е6: s = '${:1.If}М'.format(х*1е-6)
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib | 397 else: s = '${:1.0f)K'.format(x*le-3) return s formatter = FuncFormatter(currency) Затем мы можем применить эту функцию форматирования к меткам на графике (рис. 21.7). Для этого нам поможет атрибут Axes.xaxis. Он позволяет вам выполнять действия на определенной оси графика. In [11]: fig, ах = pit.subplots(figsize=(8, 5)) ax.barh(group_names, group_data) labels = ax.get_xticklabels() plt.setpflabels, rotation=45, horizontalalignment='right') ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', title='Company Revenue') ax.xaxis.set_maj or_formatter(formatter) Рис. 21.7. Отформатированные метки на оси х 21.6. Добавление элементов на график Мы можем нарисовать несколько дополнительных элементов на объекте Axes. Для этого нам просто нужно вызвать другой метод построения на том же объекте. До­ бавим среднее значение в виде вертикальной линии (рис. 21.8). In [12]: fig, ах = pit.subplots(figsize=(9, 6)) ax.barh(group_names, group_data) labels = ax.get_xticklabels() pit.setp(labels, rotation=45, horizontalalignment= 'right')
398 | Гпава 21 ах.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', title='Company Revenue') ax.xaxis.set_maj or_formatter(formatter) # Добавляем вертикальную линию, задавая стиль в вызове ax.axvline(group_mean, ls='—', color='b') Out[12]: «matplotlib.lines.Line2D at 0xlfeeaadf088> Рис. 21.8. Добавленное среднее значение на графике 21.7. Форматирование текста на графике Теперь рассмотрим, как можно отформатировать различные текстовые элементы на графике. У Matplotlib есть поистине неограниченные возможности для изменения размера шрифта, положения текста, аннотации, цвета и прочих свойств текстовых элементов, добавляемых на график. Попробуем некоторые изменения форматиро­ вания в действии. Они особенно полезны при окончательной обработке графика перед его сохранением для публикации, печати или иного использования. В Matplotlib поддерживается широкий диапазон инструментов для работы с тек­ стом, включая математические выражения, TrueType шрифты, перенос строк, про­ извольный поворот и поддержку Unicode. Поскольку шрифты могут быть встроены непосредственно в выходные документы, например в PostScript или PDF, на печати вы получите ровно то же, что и было на экране при разработке.
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib | 399 21.7.1. Базовые команды для работы с текстом Для создания текста с помощью Pyplot API или объектно-ориентированного API используются следующие команды, представленные в табл. 21.1. ТАБЛИЦА 21.1 Pyplot API OO API Описание text() text() Добавляет текст в произвольном месте графика Annotate() annotate() Добавляет аннотацию с необязательной стрелкой в произвольном месте графика xlabel () set_xlabel() Добавляет метку к оси х ylabel() set_ylabel() Добавляет метку к оси у titled set_title() Добавляет заголовок к графику figtext() text() Добавляет текст в произвольном месте рисунка suptitle() suptitle() Добавляет общий заголовок на рисунок Все эти функции и методы создают и возвращают объект Text, для которого можно настроить различные шрифты и другие свойства. В приведенном примере показаны все эти команды в действии (рис. 21.9). In [13]: fig = pit.figure() ax = fig.add_subplot(111) fig.subplots_adjust(top=0.85) # установка заголовка для рисунка и графика соответственно fig.suptitle('Заголовок рисунка', fontsize=14, fontweight='bold' ) ах.set_title('Заголовок графика') ах.set_xlabel('xlabel') ах. set_ylabel (' ylabel') # установка ограничений по осям х и у на [0, 10] # вместо значения по умолчанию [0, 1] ax.axis([0, 10, 0, 10]) ах.text (3, 8, 'Курсивный текст на плашке', style='italic', bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10)) ax.text(2, 6, г'Уравнение: $Е=шсЛ2$', fontsize=15) ax.text(3, 2, 'Unicode: Institut fur Festkorperphysik' ) ax.text(0.95, 0.01, 'Цветной текст', verticalalignment='bottom',
400 | Гпава 21 horizontalalignment= 'right', transform=ax.transAxes, color='green', fontsize=15) ax.plot([2], [1], 'o') ax.annotate('Аннотация', xy=(2, 1), xytext=(3, 4), arrowprops=dict(facecolor='black', shrink=0.05)) pit.show() Заголовок рисунка xlabel Рис. 21.9. Разное форматирование текста Теперь применим некоторые из этих возможностей к нашей диаграмме, над кото­ рой мы уже начали работать (рис. 21.10). In [14]: fig, ах = pit.subplots() # построение диаграммы и средней линии ах.barh(group_names, group_data) group_mean = np.mean(group_data) # установка ограничений и меток ах.set_xlim([-10000, 140000]) ах.set(title='2O14 Revenue', xlabel='Total Revenue', ylabel='Customer') # добавление текста среднего значения ax.axvline(x=group_mean, color='b', label='Average', linestyle='—', linewidth=l)
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib | 401 # подписи к новым клиетам for х in [3, 5, 8]: ах.text(125000, х, "New Customer") # форматирование меток formatter = FuncFormatter(currency) ax.xaxis.set_maj or_formatter(formatter) # вывод легенды ax.legend().set_visible(True) 2014 Revenue Рис. 21.10. Диаграмма с разными текстовыми элементами 21.8. Сохранение графика в файл Теперь, когда мы довольны результатом построения, сохраним его в файл. Matplotlib позволяет выполнять сохранение в разные форматы файлов. Чтобы уви­ деть список доступных вариантов, выполните вот такой код: In [15]: print(fig.canvas.get_supported_filetypes()) ('ps': 'Postscript', 'eps': 'Encapsulated Postscript', 'pdf': 'Portable Document Format', 'pgf: 'PGF code for LaTeX', 'png': 'Portable Network Graphics', 'raw': 'Raw RGBA bitmap', 'rgba': 'Raw RGBA bitmap', 'svg': 'Scalable Vector Graphics', 'svgz': 'Scalable Vector Graphics', 'jpg': 'Joint Photographic Experts Group', 'jpeg': 'Joint Photographic Experts Group', 'tif: 'Tagged Image File Format', 'tiff: 'Tagged Image File Format'} Затем с помощью метода Figure.savefig() вы можете сохранить рисунок на диск. Обратите внимание, что вам доступно несколько полезных флагов: ♦ делает фон сохраненного рисунка прозрачным, если выбран­ ный формат поддерживает прозрачность; transparent=True —
402 ♦ | Гпава 21 dpi=300 — контролирует разрешение (точек на квадратный дюйм) выходного рисунка; ♦ bbox_inches="tight" — In [16]: границы рисунка. fig.savefig('sales.jpg', transparent=False, dpi=300, bbox_inches="tight") В вашей рабочей папке должен появиться новый файл sales.jpg. 21.9. Примеры графиков 21.9.1. Гистограмма Метод hist о автоматически генерирует гистограммы и возвращает вычисленные вероятности. В дополнение к самой гистограмме (рис. 21.11) в этом примере про­ демонстрированы еще несколько функций: ♦ установка количества столбцов данных; ♦ флаг нормализации, который нормализует высоту столбцов так, чтобы интеграл гистограммы был равен 1. Полученная гистограмма является приближением функции плотности вероятности; ♦ установка цвета столбцов. In [17]: In [18]: pit.style.use("default") import matplotlib import numpy as np import matplotlib.pyplot as pit np.random.seed(19680801) # пример данных mu = 100 # среднее значение распределения sigma =15 # стандартное отклонение распределения х - mu + sigma * np.random.randn(437) num_bins =50 fig, ax = pit.subplots() # гистограмма n, bins, patches = ax.hist (x, num_bins, density=l) # добавление кривой распределения у = ((1 / (np.sqrt(2 * np.pi) * sigma)) * np.exp(-0.5 * (1 / sigma * (bins - mu))**2)) ax.plot(bins, y, '—') ax.set_xlabel('Smarts')
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib | 403 ах.set_ylabel('Probability density') ах.set_title(г'Histogram of IQ: $\mu=100$, $\sigma=15$') # настройка интервала так, чтобы не обрезать ylabel fig.tight_layout О pit.show() Рис. 21.11. Гистограмма с кривой распределения 21.9.2. Кривые и ломаные линии В Matplotlib вы можете строить произвольные ломаные линии с помощью модуля matplotlib.path. В этом примере показано, как создавать объекты In [19]: import matplotlib.path as mpath import matplotlib.patches as mpatches import matplotlib.pyplot as pit fig, ax = pit.subplots!) Path = mpath.Path path_data = [ (Path.MOVETO, (1.58, -2.57)), (Path.CURVE4, (0.35, -1.1)), (Path.CURVE4, (-1.75, 2.0)), (Path.CURVE4, (0.375, 2.0)), (Path.LINETO, (0.85, 1.15)), (Path.CURVE4, (2.2, 3.2)), (Path.CURVE4, (3, 0.05)), Path и PathPatch (рис. 21.12).
404 | Гпава 21 (Path.CURVE4, (2.0, -0.5)), (Path.CLOSEPOLY, (1.58, -2.57)), ] codes, verts = zip(*path_data) path = mpath.Path(verts, codes) patch = mpatches.PathPatch(path, facecolor='r', alpha=0.5) ax.add_patch(patch) # построение контрольных точек и соединительных линий х, у = zip(*path.vertices) line, = ax.plot(x, y, 'go-') ax.grid() ax.axis('equal') pit.show() Рис. 21.12. Пример графика с кривыми и ломаными линиями 21.9.3. Трехмерные графики Набор инструментов mpiot3d поддерживает простые трехмерные графики, включая поверхностные, каркасные, точечные и гистограммы. Нарисуем трехмерную поверхность с наложенной цветовой картой (рис. 21.13). Поверхность сделана непрозрачной с помощью параметра antialiased = False. Здесь же демонстрируется инструмент LinearLocator и настраиваемое форматирование меток по оси z. In [20]: import matplotlib.pyplot as pit from matplotlib import cm from matplotlib.ticker import LinearLocator, FormatStrFormatter from mpl_toolkits.mplot3d import Axes3D import numpy as np
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib | 405 fig = pit.figure() ах = fig.add_subplot(projection='3d') # создание данных X = np.arange(-5, 5, 0.25) Y = np.arange(-5, 5, 0.25) X, Y = np.meshgrid(X, Y) R = np.sqrt(X**2 + Y**2) Z = np.sin(R) # построение поверхности surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, linewidth=0, antialiased=False) # настройка оси z ax.set_zlim(-1.01, 1.01) ax.zaxis.set_major_locator(LinearLocator(10)) ax.zaxis.set_major_formatter(FormatStrFormatter(1 %.02f')) # добавление легенды с цветами и их значениями fig.colorbar(surf, shrink=0.5, aspect=5) pit.show() 0.5 o.o -0.5 Рис. 21.13. Пример трехмерного графика с цветовой картой 21.9.4. Круговая диаграмма Метод pie () позволяет создавать круговые диаграммы. При построении таких диа­ грамм также доступно автоматическое обозначение процента площади, отделение одного или нескольких срезов от центра диаграммы и эффект тени. Внимательно изучите прилагаемый код, в котором построение выполняется всего в несколько строк кода.
406 Гпава 21 | В дополнение к базовой круговой диаграмме мы продемонстрируем несколько дополнительных функций (рис. 21.14): ♦ метки к срезам; ♦ автоматическая подпись процентов; ♦ смещение среза от центра диаграммы; ♦ тень; ♦ настраиваемый начальный угол. Примечание По умолчанию начальный угол равен 0, т. е. начало среза Frogs пришлось бы на поло­ жительную ось х. В этом примере задается startangle = 90, поэтому вся диаграмма по­ ворачивается на 90° против часовой стрелки, а срез Frogs начинается на положитель­ ной оси у. In [21]: import matplotlib.pyplot as pit # круговая диаграмма co срезами против часовой стрелки labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' sizes = [15, 30, 45, 10] explode = (0, 0.1, 0, 0) # сместить только 2-й срез ('Hogs') figl, axl = pit.subplots() axl.pie(sizes, explode=explode, labels=labels, autopct='%l.lf%%', shadow=True, startangle=90) axl.axis('equal') # равное соотношение гарантирует, # что диаграмма будет в виде круга pit.show() Рис. 21.14. Пример круговой диаграммы
Визуализация с помощью объектно-ориентированного интерфейса в Matplotlib | 407 21.9.5. Пример построения нескольких графиков Вы можете объединить несколько графиков на одном рисунке, даже если они раз­ ных типов (рис. 21.15). In [22]: import matplotlib.pyplot as pit import numpy as np np.random.seed(19680801) data = np.random.randn (2, 100) fig, axs = pit.subplots (2, 2, figsize=(5, 5)) axs[0, 0].hist(data[0]) axs[l, 0].scatter(data[0], data[l]) axs[0, 1].plot(data[0], data[l]) axs[l, 1],hist2d(data[0], data[l]) pit. show () Рис. 21.15. Графики разных типов на одном рисунке 21.10. Резюме В этой главе мы изучили многие аспекты визуализации, собранные вместе на рис. 21.16. Это изображение любезно предоставлено сайтом pbPython.com, из ма­ териалов которого я черпал вдохновение для этой главы, и он же является офици­ альным руководством по Matplotlib. Названия переменных могут отличаться.
408 | Гпава 21 matplotlib customization example fig, (ax0, axl) = plt.subplots(nrows=l,ncols=2, sharey=True, figsize=(7, 4)) fig.suptitle('2014 Sales Analysis', fontsize=14, fontweight=‘bold') top 10.plot(kind='barh', y="Purchases' x="Name", ax=axl) top...; Analysis Units axl.axvline(x=avg, color='b' label='Average', linestyle=' linewidth=l) 40 50000 100000 40 60 80 Total units ax0.set_xlim([-10008, 140Q00]) ax0.set(title='Revenue', xlabel=’Total Revenue', ylabel=’Customers') axl.set(title='Units', xlabel='Total Units’, ylabel='') fig.savefig('sales.png', transparent=False, dpi=80, bbox_inches="tight") pbpython.com Рис. 21.16. Пример рисунка из Matplotlib
Ответы на вопросы «Правда или ложь» Глава 1. Введение в Data Science и основы программирования 5. Ложь 6. Ложь 1. Правда 7. Ложь 2. Ложь 8. Правда 3. Ложь 9. Ложь 4. Правда 10. Правда 5. Ложь 6. Ложь 7. Правда 8. Ложь 9. Правда 10. Ложь Глава 4. Объекты и операторы в Python 1. Правда 2. Ложь 3. Правда 4. Правда Глава 2. Введение в Python 5. Ложь 1. Ложь 6. Ложь 2. Правда 7. Правда 3. Ложь 8. Правда 4. Ложь 9. Ложь 5. Ложь 10. Правда 6. Правда 7. Ложь 8. Правда 9. Правда 10. Ложь Глава 3. Основы Python Глава 5. Операторы управления потоком 1. Ложь 2. Правда 3. Ложь 4. Правда 1. Ложь 5. Правда 2. Правда 6. Правда 3. Ложь 7. Правда 4. Ложь 8. Правда
410 | Ответы на вопросы «Правда или ложь» 9. Ложь 9. Ложь 10. Правда 10. Ложь Глава 6. Функции Глава 11. Классы 1. Правда 1. Правда 2. Правда 2. Правда 3. Ложь 3. Правда 4. Правда 4. Ложь 5. Ложь 5. Правда 6. Правда 6. Правда 7. Ложь 7. Правда 8. Ложь 9. Правда 10. Правда Глава 8. Структуры данных и последовательности 1. Ложь 2. Правда 8. Ложь 9. Правда 10. Ложь Глава 12. Ошибки и обработка исключений 1. Правда 2. Правда 3. Ложь 3. Ложь 4. Правда 4. Ложь 5. Правда 5. Ложь 6. Ложь 6. Правда 7. Правда 7. Правда 8. Ложь 8. Правда 9. Ложь 9. Правда 10. Правда 10. Правда Глава 9. Ввод-вывод данных и работа с файлами Глава 13. Модули и пакеты 1. Ложь 2. Ложь 1. Ложь 3. Правда 2. Правда 4. Правда 3. Ложь 5. Ложь 4. Правда 6. Правда 5. Правда 7. Правда 6. Ложь 8. Правда 7. Ложь 9. Правда 8. Ложь 10. Правда
Библиография 1. Alammar, Jay. A Visual Intro to NumPy and Data Representation. 2019. URL: http://jalammar.github.io/visual-numpy/ (дата обращения: 24.06.2020). 2. Anaconda. Installing on macOS. 2020. URL: https://docs.anaconda.com/anaconda/install/mac-os/ (дата обращения: 17.06.2020). 3. Anaconda. Installing on Windows. 2020. URL: https://docs.anaconda.com/anaconda/install/windows/ (дата обращения: 17.06.2020). 4. AskPython. Polymorphism in Python. 2020. URL: https://www.askpython.com/python/oops/polymorphism-in-python (дата обращения: 20.06.2020). 5. Bokeh. Quickstart. 2019. URL: https://docs.bokeh.org/en/latest/ (дата обращения: 30.06.2020). 6. GeeksforGeeks. Python Dictionary. 2020. URL: https://www.geeksforgeeks.org/python-dictionary/ (дата обращения: 19.06.2020). 7. McIntire, George, Martin, Brendan, Washington, Lauren. Pandas Tutorial: A Complete Introduction for Beginners. 2020. URL: https://www.leamdatasci.com/tutorials/python-pandas-tutorial-completeintroduction-for-beginners/ (дата обращения: 24.06.2020). 8. IPython. A Qt Console for IPython. 2020. URL: https://ipython.org/ ipython-doc/3/interactive/qtconsole.html (дата обращения: 17.06.2020). 9. Jupyter. The Jupyter Notebook. 2015. URL: https://jupyternotebook.readthedocs.io/en/stable/notebook.html (дата обращения: 17.06.2020). 10. Kaushik, Shruti. Python Interpreters. 2020. URL: https://hackr.io/blog/ python-interpreters (дата обращения: 17.06.2020). 11. Magee, John. Python Debugging (fixing problems). 2019. URL: https://www.cs.bu.edu/courses/csl 08/guides/debug.html (дата обращения: 18.06.2020). 12. Marr, Bernard. A Brief History of Big Data Everyone Should Read. 2015. URL: https://www.linkedin.com/pulse/brief-history-big-data-everyone-should-readbemard-marr/ (дата обращения: 16.06.2020). 13. Matplotlib development team. History. 2020. URL: https://matplotlib.Org/3.2.2/users/history.html (дата обращения: 02.07.2020).
412 | Библиография 14. Matplotlib development team, matplotlib.pyplot.plot. 2020. URL: https://matplotlib.Org/3.1. l/api/_as_gen/matplotlib.pyplot.plot.html (дата обращения: 02.07.2020). 15. Matplotlib development team. Pyplot tutorial. 2020. URL: https://matplotlib.Org/3.2.2/tutorials/introductory/pyplot.html (дата обращения: 02.07.2020). 16. Matplotlib development team. The Lifecycle of a Plot. 2020. URL: https://matplotlib.Org/3.2.1/tutorials/introductory/lifecycle.html (дата обращения: 02.07.2020). 17. Matplotlib development team. Usage Guide. 2020. URL: https://matplotlib.Org/3.2.1/tutorials/introductory/usage.html (дата обращения: 02.07.2020). 18. Programiz. Python break and continue. 2020. URL: https://www.programiz.com/python-programming/break-continue (дата обращения: 18.06.2020). 19. Programiz. Python Functions. 2020. URL: https://www.programiz.com/ python-programming/function (дата обращения: 18.06.2020). 20. Python Reference Manual. The standard type hierarchy. 2002. URL: https://docs.python.Org/2.l/ref/types.html (дата обращения: 18.06.2020). 21. Python Software Foundation. An Informal Introduction to Python. 2020. URL: https://docs.python.Org/3/tutorial/introduction.html (дата обращения: 18.06.2020). 22. Python Software Foundation. Built-in Functions. 2020. URL: https://docs.python.Org/3/library/functions.html (дата обращения: 18.06.2020). 23. Python Software Foundation. Classes. 2020. URL: https://docs.python.Org/3/tutorial/classes.html (дата обращения: 20.06.2020). 24. Python Software Foundation. Data model. 2020. URL: https://docs.python.Org/3.8/reference/datamodel.html (дата обращения: 18.06.2020). 25. Python Software Foundation. Data Structures. 2020. URL: https://docs.python.Org/3/tutorial/datastructures.html (дата обращения: 19.06.2020). 26. Python Software Foundation. Errors and Exceptions. 2020. URL: https://docs.python.Org/3/tutorial/errors.html (дата обращения: 21.06.2020). 27. Python Software Foundation. General Python FAQ. 2020. URL: https://docs.python.Org/3.8/faq/general.html#id27 (дата обращения: 17.06.2020). 28. Python Software Foundation. Input and Output. 2020. URL: https://docs.python.Org/3/tutorial/inputoutput.html (дата обращения: 19.06.2020). 29. Python Software Foundation. Modules. 2020. URL: https://docs.python.Org/3/tutorial/modules.html (дата обращения: 22.06.2020). 30. Python Software Foundation. More Control Flow Tools. 2020. URL: https://docs.python.Org/3/tutorial/controlflow.html (дата обращения: 18.06.2020).
Библиография | 413 31. Python Software Foundation. The Python Tutorial. 2020. URL: https://docs.python.Org/3/tutorial/index.html (дата обращения: 16.06.2020). 32. Python Software Foundation. The Python Tutorial — Whetting Your Appetite. 2020. URL: https://docs.python.Org/3.8/tutorial/appetite.html (дата обращения: 17.06.2020). 33. Robinson, David, gleam. 2014. URL: https://github.com/dgrtwo/gleam (дата обращения: 01.07.2020). 34. SCALA Blockchain. Python. 2019. URL: https://www.scalablockchain.com/python.html (дата обращения: 17.06.2020). 35. Solomon, Brad. Python Plotting With Matplotlib (Guide). 2020. URL: https://realpython.com/python-matplotlib-guide/ (дата обращения: 02.07.2020). 36. Spyder. The Scientific Python Development Environment — Documentation. 2018. URL: https://docs.spyder-ide.org/index.html (дата обращения: 17.06.2020). 37. Spyder. Sypder Docs Editor. 2020. URL: https://docs.spyder-ide.org/editor.html (дата обращения: 17.06.2020). 38. Story, Rob. Folium. 2013. URL: https://python-visualization.github.io/folium/ (дата обращения: 30.06.2020). 39. Swaroop, С. H. A Byte of Python. 2003. URL: https://python.swaroopch.com/ (дата обращения: 02.07.2020). 40. Tagliaferri, Lisa. Python 2 vs Python 3: Practical Considerations. 2016. URL: https://www.digitalocean.com/community/tutorials/python-2-vs-python-3-practicalconsiderations-2 (дата обращения: 17.08.2020). 41. Pandas development team. Getting started tutorials. 2020. URL: https ://pandas .pydata. org/pandasdocs/version/1.0.4/getting_started/intro_tutorials/index.html (дата обращения: 24.06.2020). 42. Pandas development team. How to create new columns derived from existing columns? 2020. URL: https://pandas.pydata.org/docs/getting_started/intro_tutorials/05_add columns.html (дата обращения: 30.06.2020). 43. Pandas development team. How to create plots in Pandas? 2020. URL: https://pandas.pydata.org/pandasdocs/stable/getting_started/intro_tutorials/04_plotting.html (дата обращения: 30.06.2020). 44. Pandas development team. Pandas documentation. 2020. URL: https://pandas.pydata.org/pandas-docs/version/ ! .0.4/ (дата обращения: 24.06.2020). 45. SciPy community. NumPy: the absolute basics for beginners. 2020. URL: https://numpy.org/devdocs/user/absolute_beginners.html (дата обращения: 23.06.2020).
414 | Библиография 46. SciPy community. Quickstart tutorial. 2020. URL: https://numpy.org/doc/L17/user/quickstart.html (дата обращения: 23.06.2020). 47. W3Schools. Python assert Keyword. 2020. URL: https://w3schoolsrus.github.io/python/ref_keyword_assert.html (дата обращения: 21.06.2020). 48. W3Schools. Python Sets. 2020. URL: https://www.w3schools.com/python/python_sets.asp (дата обращения: 19.06.2020). 49. Waskom, Michael. An introduction to seaborn. 2020. URL: https://seabom.pydata.org/introduction.html (дата обращения: 30.06.2020). 50. Wikipedia. History of Python. 2020. URL: https://en.wikipedia.org/w/index.php?title=History_of_Python (дата обращения: 17.06.2020). 51. Wikipedia. Python (programming language). 2020. URL: https://en.wikipedia.org/w/index.php?title=Python_(programming_language ) (дата обращения: 16.06.2020).
Гэддис Т. www.bhv.ru Начинаем программировать на Python, 5-е изд. Отдел оптовых поставок: e-mail: opt@bhv.ru НАЧИНАЕМ ПРОГРАММИРОВАТЬ ".»> PYTHON" • Краткое введение в компьютеры и программирование • Ввод, обработка и вывод данных • Управляющие структуры и булева логика • Структуры с повторением и функции • Файлы и исключения • Списки и кортежи • Строковые данные, словари и множества • Классы и объектно-ориентированное программирование • Наследование и рекурсия • Функциональное программирование • Программирование баз данных В книге изложены принципы программирования, с помощью которых вы приобре­ тете навыки алгоритмического решения задач на языке Python, даже если у вас нет опыта программирования. Для облегчения понимания сути алгоритмов широко ис­ пользованы блок-схемы, псевдокод и другие инструменты. Приведено большое ко­ личество сжатых и практичных примеров программ. В каждой главе предложены тематические задачи с пошаговым анализом их решения. Отличительной особенностью издания является его ясное, дружественное и легкое для понимания изложение материала. Книга идеально подходит для вводного курса по программированию и разработке программного обеспечения на языке Python. Тони Гэддис, ведущий автор всемирно известной серии книг «Начинаем программировать...» (Starting Out With) с двадцатилетним опытом преподавания курсов информатики в колледже округа Хейвуд, шт. Северная Каролина, удостоен звания «Преподаватель года», лауреат пре­ мии «Педагогическое мастерство».
ИНТЕРНЕТ-МАГАЗИН BHV.RU КНИГИ,РОБОТЫ, ЭЛЕКТРОНИКА Интернет-магазин издательства «БХВ» • Более 25 лет на российском рынке • Книги и наборы по электронике и робототехнике по ■ Электронные архивы и компакт-дисков • Ответы на
PYTHON— это просто Пошаговое руководство по программированию и анализу данных ■ Исследуйте возможности Python с использованием дистрибутива Anaconda ■ Узнайте, как установит^. и использовать Python на своем компьютере ■ Создавайте свои переменные, объекты и изучите их синтаксис ■ Изучите встроенные типы объектов Python, такие как строки, списки, кортежи, множества и словари ■ Научитесь вызывать встроенные функции, а также писать свои собственные ■ Организуйте свой код и другие объекты в более крупные компоненты с помощью модулей ■ Исследуйте классы — инструмент объектно-ориентированного программирования ■ Пишите сложный код, научитесь обрабатывать ошибки и исключения ■ Узнайте о массивах NumPy и операциях с ними ■ Изучите анализ данных с помощью Pandas ■ Погрузитесь в захватывающий мир визуализации с использованием Matplotlib ■ Научитесь создавать приложения Python с графическим интерфейсом Изучите программирование на Python, начиная с самых основ и заканчивая использованием би­ блиотек для анализа данных и визуа­ лизации. Эта книга поможет освоить Python как абсолютным новичкам, так и опытным программистам, знакомым с другими языками. В нее включены все актуальные на сегод­ няшний день расширения Python. д s Ci Л S3 Нилаб Нисчал имеет степень магистра менеджмента, работает штатным специалистом по маркетингу и ведущим аналитиком данных на протяжении более 14 лет. Он обучает студентов колледжей как в инженерной области, так и в области управления. Страсть к принятию осмысленных бизнес-решений на основе анализа данных привела его к глубокому изучению языков R и Python. Результатом данных изысканий и стала эта книга. PYTHON — это просто Пошаговое руководство по программированию и анализу данных 191036, Санкт-Петербург, Гончарная уп„ 20 Тел.: (812) 717-10-50, 339-54-17, 339-54-28 E-mail: mail@bhv.ru Internet: www.bhv.ru Нилаб Нисчал %