оглавление Предисловие..................................................................17 На кого рассчитана эта книга........................................................................ 18 На кого эта книга не рассчитана.................................................................... 18 Как организована эта книга........................................................................... 18 Практикум..................................................................................................... 20 Как производился хронометраж.................................................................... 21 Поговорим: мое личное мнение.................................................................... 21 Терминология Python.................................................................................... 22 Использованная версия Python..................................................................... 22 Графические выделения............................................................................... 22 О примерах кода........................................................................................... 23 Как с нами связаться..................................................................................... 23 Благодарности.............................................................................................. 24 ЧАСТЬ I. Пролог...............................................................27 Глава 1. Модель данных в языке Python...............................28 Колода карт на Python............................................................................ 29 Как используются специальные методы................................................ 33 Эмуляция числовых типов...................................................................... 33 Строковое представление..................................................................... 35 Арифметические операторы.................................................................. 36 Булево значение пользовательского типа.............................................. 37 Сводка специальных методов................................................................ 37 Почему len – не метод............................................................................ 39 Резюме.................................................................................................. 40 Дополнительная литература.................................................................. 40 ЧАСТЬ II. Структуры данных...............................................43 Глава 2. Массив последовательностей................................44 Общие сведения о встроенных последовательностях............................ 45 Списковое включение и генераторные выражения................................ 46 Списковое включение и удобочитаемость..................................................... 46 Сравнение спискового включения с map и filter............................................. 48 Декартовы произведения.............................................................................. 49 Оглавление 7 Генераторные выражения.............................................................................. 50 Кортеж – не просто неизменяемый список............................................ 52 Кортежи как записи....................................................................................... 52 Распаковка кортежа...................................................................................... 53 Использование * для выборки лишних элементов.................................. 54 Распаковка вложенного кортежа................................................................... 55 Именованные кортежи.................................................................................. 56 Кортежи как неизменяемые списки............................................................... 57 Получение среза.................................................................................... 59 Почему в срезы и диапазоны не включается последний элемент................... 59 Объекты среза.............................................................................................. 59 Многомерные срезы и многоточие................................................................ 61 Присваивание срезу..................................................................................... 61 Использование + и * для последовательностей..................................... 62 Построение списка списков.......................................................................... 63 Составное присваивание последовательностей.................................... 64 Головоломка: присваивание A += .................................................................. 66 Метод list.sort и встроенная функция sorted.......................................... 68 Средства работы с упорядоченными последовательностями в модуле bisect...................................................................................... 70 Поиск средствами bisect............................................................................... 70 Вставка с помощью функции bisect.insort...................................................... 73 Когда список не подходит...................................................................... 74 Массивы....................................................................................................... 74 Представления областей памяти.................................................................. 78 Библиотеки NumPy и SciPy............................................................................ 79 Двусторонние и другие очереди.................................................................... 81 Резюме.................................................................................................. 85 Дополнительная литература.................................................................. 86 Глава 3. Словари и множества. ..........................................91 Общие типы .................................................... 91 Словарное включение............................................................................ 94 Обзор наиболее употребительных методов отображений...................... 94 Обработка отсутствия ключей с помощью setdefault...................................... 97 Отображения с гибким поиском по ключу.............................................. 99 defaultdict: еще один подход к обработке отсутствия ключа........................... 99 Метод __missing__........................................................................................101 Вариации на тему dict.......................................................................... 103 Создание подкласса UserDict.............................................................. 105 Неизменяемые отображения............................................................... 106 Теория множеств................................................................................. 108 Литеральные множества..............................................................................109 Множественное включение..........................................................................111 8 Оглавление Операции над множествами.........................................................................111 Под капотом dict и set.......................................................................... 114 Экспериментальная демонстрация производительности.............................115 Хэш-таблицы в словарях..............................................................................117 Практические последствия механизма работы dict...................................................................................................120 Как работают множества – практические следствия.....................................123 Резюме................................................................................................ 123 Дополнительная литература................................................................ 124 Поговорим........................................................................................... 124 Глава 4. Текст и байты.................................................... 126 О символах и не только........................................................................ 127 Все, что нужно знать о байтах.............................................................. 128 Структуры и представления областей памяти..............................................131 Базовые кодировщики и декодировщики............................................. 132 Проблемы кодирования и декодирования............................................ 134 Обработка UnicodeEncodeError....................................................................134 Обработка UnicodeDecodeError....................................................................135 Исключение SyntaxError при загрузке модулей и неожиданной кодировкой..................................................................................................136 Как определить кодировку последовательности байтов...............................138 BOM: полезный крокозябр...........................................................................139 Обработка текстовых файлов............................................................... 140 Кодировки по умолчанию: сумасшедший дом..............................................143 Нормализация Unicode для правильного сравнения............................ 146 Сворачивание регистра...............................................................................149 Служебные функции для сравнения нормализованного текста.....................150 Экстремальная «нормализация»: удаление диакритических знаков.............151 Сортировка Unicode-текстов............................................................... 154 Сортировка с помощью алгоритма упорядочивания Unicode........................156 База данных Unicode............................................................................ 157 Двухрежимный API............................................................................... 159 str и bytes в регулярных выражениях............................................................159 str и bytes в функциях из модуля os...............................................................160 Резюме................................................................................................ 162 Дополнительная литература................................................................ 164 Поговорим........................................................................................... 166 ЧАСТЬ III. Функции как объекты........................................ 169 Глава 5. Полноправные функции...................................... 170 Обращение с функцией как с объектом................................................ 171 Функции высшего порядка................................................................... 172 Современные альтернативы функциям map, filter и reduce...........................173 Оглавление 9 Анонимные функции............................................................................ 175 Семь видов вызываемых объектов....................................................... 176 Пользовательские вызываемые типы................................................... 177 Интроспекция функций........................................................................ 178 От позиционных к чисто именованным параметрам............................. 180 Получение информации о параметрах................................................. 182 Аннотации функций............................................................................. 186 Пакеты для функционального программирования............................... 188 Модуль operator...........................................................................................188 Фиксация аргументов с помощью functools.partial........................................191 Резюме................................................................................................ 193 Дополнительная литература................................................................ 194 Поговорим........................................................................................... 195 Глава 6. Реализация паттернов проектирования с помощью полноправных функций.................................................. 198 Практический пример: переработка паттерна Стратегия..................... 199 Классическая Стратегия..............................................................................199 Функционально-ориентированная стратегия....................................... 203 Выбор наилучшей стратегии: простой подход..............................................206 Поиск стратегий в модуле............................................................................207 Паттерн Команда................................................................................. 208 Резюме................................................................................................ 210 Дополнительная литература................................................................ 211 Поговорим........................................................................................... 212 Глава 7. Декораторы функций и замыкания........................ 214 Краткое введение в декораторы.......................................................... 215 Когда Python выполняет декораторы.................................................... 216 Паттерн Стратегия, дополненный декоратором................................... 218 Правила видимости переменных......................................................... 219 Замыкания........................................................................................... 222 Объявление nonlocal............................................................................ 225 Реализация простого декоратора........................................................ 227 Как это работает..........................................................................................228 Декораторы в стандартной библиотеке............................................... 230 Кэширование с помощью functools.lru_cache...............................................230 Одиночная диспетчеризация и обобщенные функции..................................233 Композиции декораторов.................................................................... 236 Параметризованные декораторы......................................................... 236 Параметризованный регистрационный декоратор.......................................237 Параметризованный декоратор clock...........................................................239 10 Оглавление Резюме................................................................................................ 241 Дополнительная литература................................................................ 242 Поговорим........................................................................................... 243 ЧАСТЬ IV. Объектно-ориентированные идиомы.................. 247 Глава 8. Ссылки на объекты, изменяемость и повторное использование.............................................................. 248 Переменные – не ящики...................................................................... 249 Тождественность, равенство и синонимы............................................ 250 Выбор между == и is.....................................................................................252 Относительная неизменяемость кортежей...................................................253 По умолчанию копирование поверхностное......................................... 254 Глубокое и поверхностное копирование произвольных объектов.................256 Параметры функций как ссылки........................................................... 258 Значения по умолчанию изменяемого типа: неудачная мысль......................259 Защитное программирование при наличии изменяемых параметров..........261 del и сборка мусора............................................................................. 263 Слабые ссылки.................................................................................... 265 Коллекция WeakValueDictionary....................................................................266 Ограничения слабых ссылок........................................................................268 Как Python хитрит с неизменяемыми объектами.................................. 269 Резюме................................................................................................ 270 Дополнительная литература................................................................ 271 Поговорим........................................................................................... 272 Глава 9. Объект в духе Python. ......................................... 276 Представления объекта....................................................................... 277 И снова класс вектора......................................................................... 277 Альтернативный конструктор............................................................... 280 Декораторы classmethod и staticmethod............................................... 281 Форматирование при выводе.............................................................. 282 Хэшируемый класс Vector2d................................................................ 286 Закрытые и «защищенные» атрибуты в Python..................................... 291 Экономия памяти с помощью атрибута класса __slots__....................... 293 Проблемы при использовании __slots__.......................................................296 Переопределение атрибутов класса.................................................... 296 Резюме................................................................................................ 299 Дополнительная литература................................................................ 300 Поговорим........................................................................................... 301 Глава 10. Рубим, перемешиваем и нарезаем последовательности...................................................... 305 Оглавление 11 Vector: пользовательский тип последовательности.............................. 306 Vector, попытка № 1: совместимость с Vector2d................................... 306 Протоколы и динамическая типизация................................................. 309 Vector, попытка № 2: последовательность, допускающая срезку.......... 310 Как работает срезка.....................................................................................311 Метод __getitem__ с учетом срезов..............................................................313 Vector, попытка № 3: доступ к динамическим атрибутам...................... 315 Vector, попытка № 4: хэширование и ускорение оператора ==.............. 319 Vector, попытка № 5: форматирование................................................................................. 324 Резюме................................................................................................ 331 Дополнительная литература................................................................ 332 Поговорим........................................................................................... 333 Глава 11. Интерфейсы: от протоколов до абстрактных . базовых классов............................................................ 338 Интерфейсы и протоколы в культуре Python......................................... 339 Python в поисках следов последовательностей.................................... 341 Партизанское латание как средство реализации протокола во время выполнения........................................................................... 343 Алекс Мартелли о водоплавающих...................................................... 345 Создание подкласса ABC..................................................................... 350 ABC в стандартной библиотеке............................................................ 352 ABC в модуле collections.abc........................................................................352 Числовая башня ABC....................................................................................354 Определение и использование ABC..................................................... 355 Синтаксические детали ABC........................................................................359 Создание подклассов ABC Tombola..............................................................360 Виртуальный подкласс Tombola...................................................................363 Как тестировались подклассы Tombola................................................ 365 Использование метода register на практике......................................... 368 Гуси могут вести себя как утки............................................................. 369 Резюме................................................................................................ 371 Дополнительная литература................................................................ 373 Поговорим........................................................................................... 374 Глава 12. Наследование: хорошо или плохо....................... 380 Сложности наследования встроенным типам...................................... 380 Множественное наследование и порядок разрешения методов.......... 384 Множественное наследование в реальном мире................................. 388 Жизнь с множественным наследованием............................................ 391 Tkinter: хороший, плохой, злой.....................................................................393 12 Оглавление Современный пример: примеси в обобщенных представлениях Django................................................................................................. 395 Резюме................................................................................................ 398 Дополнительная литература................................................................ 399 Поговорим........................................................................................... 400 Глава 13. Перегрузка операторов: как правильно?.............. 403 Основы перегрузки операторов........................................................... 404 Унарные операторы............................................................................. 404 Перегрузка оператора сложения векторов +........................................ 407 Перегрузка оператора умножения на скаляр *..................................... 412 Операторы сравнения......................................................................... 416 Операторы составного присваивания.................................................. 421 Резюме................................................................................................ 425 Дополнительная литература................................................................ 426 Поговорим........................................................................................... 428 ЧАСТЬ V. Поток управления............................................. 431 Глава 14. Итерируемые объекты, итераторы и генераторы... 432 Класс Sentence, попытка № 1: последовательность слов..................... 433 Почему последовательности итерируемы: функция iter................................435 Итерируемые объекты и итераторы..................................................... 436 Класс Sentence, попытка № 2: классический вариант.......................... 440 Почему идея сделать Sentence итератором плоха........................................442 Класс Sentence, попытка № 3: генераторная функция.......................... 443 Как работает генераторная функция............................................................444 Класс Sentence, попытка № 4: ленивая реализация............................................................................ 447 Класс Sentence, попытка № 5: генераторное выражение..................... 448 Генераторные выражения: когда использовать.................................... 450 Другой пример: генератор арифметической прогрессии..................... 451 Построение арифметической прогрессии с помощью itertools.....................453 Генераторные функции в стандартной библиотеке............................... 454 yield from – новая конструкция в Python 3.3.......................................... 465 Функции редуцирования итерируемого объекта.................................. 466 Более пристальный взгляд на функцию iter.......................................... 468 Пример: генераторы в утилите преобразования базы данных.............. 469 Генераторы как сопрограммы.............................................................. 471 Резюме................................................................................................ 472 Дополнительная литература................................................................ 472 Поговорим........................................................................................... 473 Оглавление 13 Глава 15. Контекстные менеджеры и блоки else.................. 479 Делай то, потом это: блоки else вне if................................................... 480 Контекстные менеджеры и блоки with.................................................. 482 Утилиты contextlib................................................................................ 486 Использование @contextmanager........................................................ 487 Резюме................................................................................................ 490 Дополнительная литература................................................................ 491 Поговорим........................................................................................... 492 Глава 16. Сопрограммы.................................................. 494 Эволюция: от генераторов к сопрограммам........................................ 495 Базовое поведение генератора, используемого в качестве сопрограммы....................................................................................... 496 Пример: сопрограмма для вычисления накопительного среднего....... 499 Декораторы для инициализации сопрограмм...................................... 501 Завершение сопрограммы и обработка исключений........................... 502 Возврат значения из сопрограммы...................................................... 506 Использование yield from..................................................................... 508 Семантика yield from............................................................................ 514 Пример: применение сопрограмм для моделирования дискретных событий............................................................................................... 520 О моделировании дискретных событий........................................................521 Моделирование работы таксопарка.............................................................522 Резюме................................................................................................ 529 Дополнительная литература................................................................ 531 Поговорим........................................................................................... 533 Глава 17. Параллелизм и будущие объекты........................ 536 Пример: три способа загрузки из веба................................................ 536 Скрипт последовательной загрузки.............................................................538 Загрузка с применением библиотеки concurrent.futures...............................540 Где находятся будущие объекты?.................................................................542 Блокирующий ввод-вывод и GIL........................................................... 545 Запуск процессов с помощью concurrent.futures.................................. 546 Эксперименты с Executor.map.............................................................. 548 Загрузка с индикацией хода выполнения и обработкой ошибок........... 551 Обработка ошибок во flags2-примерах.........................................................556 Использование futures.as_completed............................................................558 Альтернативы: многопоточная и многопроцессная обработка............. 561 Резюме................................................................................................ 561 Дополнительная литература................................................................ 562 Поговорим........................................................................................... 564 14 Оглавление Глава 18. Применение пакета asyncio для организации конкурентной работы..................................................... 567 Сравнение потока и сопрограммы....................................................... 569 asyncio.Future: не блокирует умышленно......................................................575 Yield from из будущих объектов, задач и сопрограмм....................................576 Загрузка с применением asyncio и aiohttp............................................ 578 Объезд блокирующих вызовов............................................................. 582 Улучшение скрипта загрузки на основе asyncio.................................... 585 Использование asyncio.as_completed...........................................................585 Использование исполнителя для предотвращения блокировки цикла обработки событий............................................................................591 От обратных вызовов к будущим объектам и сопрограммам................ 592 Выполнение нескольких запросов для каждой операции загрузки...............595 Разработка серверов с помощью пакета asyncio.................................. 597 TCP-сервер на основе asyncio......................................................................598 Веб-сервер на основе библиотеки aiohttp....................................................602 Повышение степени параллелизма за счет более интеллектуальных клиентов......................................................................................................606 Резюме................................................................................................ 607 Дополнительная литература................................................................ 608 Поговорим........................................................................................... 610 ЧАСТЬ VI. Метапрограммирование................................... 613 Глава 19. Динамические атрибуты и свойства.................... 614 Применение динамических атрибутов для обработки данных.............. 615 Исследование JSON-подобных данных с динамическими атрибутами.........617 Проблема недопустимого имени атрибута...................................................620 Гибкое создание объектов с помощью метода __new__............................................................................................622 Изменение структуры набора данных OSCON с помощью модуля shelve......624 Выборка связанных записей с помощью свойств.........................................627 Использование свойств для контроля атрибутов................................. 633 LineItem, попытка № 1: класс строки заказа..................................................633 LineItem, попытка № 2: контролирующее свойство.......................................634 Правильный взгляд на свойства........................................................... 636 Свойства переопределяют атрибуты экземпляра.........................................637 Документирование свойств..........................................................................639 Программирование фабрики свойств.................................................. 640 Удаление атрибутов............................................................................. 643 Важные атрибуты и функции для работы с атрибутами........................ 644 Специальные атрибуты, влияющие на обработку атрибутов.........................645 Встроенные функции для работы с атрибутами............................................645 Специальные методы для работы с атрибутами...........................................646 Резюме................................................................................................ 648 Оглавление 15 Дополнительная литература................................................................ 648 Поговорим........................................................................................... 649 Глава 20. Дескрипторы атрибутов.................................... 653 Пример дескриптора: проверка значений атрибутов........................... 653 LineItem попытка № 3: простой дескриптор..................................................654 LineItem попытка № 4: автоматическая генерация имен атрибутов хранения......................................................................................................659 LineItem попытка № 5: новый тип дескриптора.............................................665 Переопределяющие и непереопределяющие дескрипторы................. 668 Переопределяющий дескриптор..................................................................669 Переопределяющий дескриптор без __get__................................................670 Непереопределяющий дескриптор..............................................................671 Перезаписывание дескриптора в классе......................................................673 Методы являются дескрипторами....................................................... 673 Советы по использованию дескрипторов............................................. 676 Строка документации дескриптора и перехват удаления..................... 677 Резюме................................................................................................ 678 Дополнительная литература................................................................ 679 Поговорим........................................................................................... 680 Глава 21. Метапрограммирование классов........................ 682 Фабрика классов................................................................................. 683 Декоратор класса для настройки дескрипторов................................... 686 Что когда происходит: этап импорта и этап выполнения...................... 688 Демонстрация работы интерпретатора........................................................689 Основы метаклассов........................................................................... 693 Демонстрация работы метакласса...............................................................695 Метакласс для настройки дескрипторов.............................................. 699 Специальный метод метакласса __prepare__.......................................................................................... 701 Классы как объекты............................................................................. 703 Резюме................................................................................................ 704 Дополнительная литература................................................................ 705 Поговорим........................................................................................... 707 Послесловие................................................................ 709 Дополнительная литература................................................................ 710 приложение А. Основы языка Python................................ 713 Глава 3: тест производительности оператора in................................... 713 Глава 3: сравнение битовых представлений хэшей.............................. 715 Глава 9. Потребление оперативной памяти при наличии и отсутствии __slots__.......................................................................... 716 16 Оглавление Глава 14: скрипт преобразования базы данных isis2json.py.................. 717 Глава 16: моделирование дискретных событий таксопарка.................. 722 Глава 17: примеры, относящиеся к криптографии................................ 726 Глава 17: примеры HTTP-клиентов из серии flags2............................... 729 Глава 19: скрипты и тесты для обработки набора данных OSCON......... 734 Терминология Python..................................................... 739 Предметный указатель................................................... 754 Предисловие План такой: если кто-то пользуется средством, которое вы не понимаете, просто пристрелите его. Это проще, чем учить что-то новое, и очень скоро в мире останутся только кодировщики, которые используют только всем понятное крохотное подмножество Python 0.9.6 <смешок>.1 – Тим Питерс, легендарный разработчик ядра и автор сборника поучений «The Zen of Python» «Python – простой для изучения и мощный язык программирования». Это первые слова в официальном «Пособии по Python» (https://docs.python.org/3/ tutorial/). И это правда, но не вся правда: поскольку язык так просто выучить и начать применять на деле, многие практикующие программисты используют лишь малую часть его обширных возможностей. Опытный программист может написать полезный код на Python уже через несколько часов изучения. Но вот проходят недели, месяцы – и многие разработчики так и продолжают писать на Python код, в котором отчетливо видно влияние языков, которые они учили раньше. И даже если Python – ваш первый язык, все равно авторы академических и вводных учебников зачастую излагают его, тщательно избегая особенностей, характерных только для этого языка. Будучи преподавателем, который знакомит с Python программистов, знающих другие языки, я нередко сталкиваюсь еще с одной проблемой, которую пытаюсь решить в этой книге: нас интересует только то, о чем мы уже знаем. Любой программист, знакомый с каким-то другим языком, догадывается, что Python поддерживает регулярные выражения, и начинает смотреть, что про них написано в документации. Но если вы никогда раньше не слыхали о распаковке кортежей или о дескрипторах, то, скорее всего, и искать сведения о них не станете, а в результате не будете использовать эти средства лишь потому, что они специфичны для Python. Эта книга не является полным справочным руководством по Python. Упор в ней сделан на языковые средства, которые либо уникальны для Python, либо отсутствуют во многих других популярных языках. Кроме того, в книге рассматривается в основном ядро языка и немногие библиотеки. Я редко упоминаю о паке1 Сообщение в группе Usenet comp.lang.python от 23 декабря 2002: «Acrimony in c.l.p.» (https://mail. python.org/pipermail/python-list/2002-December/147293.html). 18 Предисловие тах, не включенных в стандартную библиотеку, хотя нынче количество пакетов для Python уже перевалило за 60 000, и многие из них исключительно полезны. На кого рассчитана эта книга Эта книга написана для практикующих программистов на Python, которые хотят усовершенствоваться в Python 3. Если вы уже знакомы с Python и хотели бы перейти на версию Python 3.4 или старше, эта книга для вас. Когда я писал ее, большинство профессиональных программистов работали с Python 2, поэтому я специально выделял особенности Python 3, которые для этой аудитории могли оказаться внове. Однако поскольку книга посвящена, главным образом, тому, как получить максимум от Python 3.4, я не останавливаюсь на исправлениях, которые нужно внести в старый код, чтобы он продолжал работать. Большинство примеров будут работать в Python 2.7 с минимальными изменениями или вообще без оных, но иногда обратный перенос требует значительных усилий. И все же я полагаю, что эта книга может быть полезна и тем, кто вынужден продолжать писать на Python 2.7, поскольку базовые концепции остались теми же самыми. Python 3 – не новый язык, и большинство различий можно изучить за полдня. Желающие узнать, что нового появилось в Python 3.0, могут начать со страницы https://docs.python.org/3.0/whatsnew/3.0.html. Разумеется, с момента выхода версии 3.0 в 2009 году Python не стоял на месте, но все последующие изменения не так существенны, как внесенные в 3.0. Если вы не уверены в том, достаточно ли хорошо знаете Python, чтобы читать эту книгу, загляните в оглавление официального «Пособия по Python» (https://docs.python.org/3/tutorial/). Темы, рассмотренные в пособии, в этой книге не затрагиваются, за исключением некоторых новых средств, появившихся в Python 3. На кого эта книга не рассчитана Если вы только начинаете изучать Python, это книга покажется вам сложноватой. Более того, если вы откроете ее на слишком раннем этапе путешествия в мир Python, то может сложиться впечатление, будто в каждом Python-скрипте следует использовать специальные методы и приемы метапрограммирования. Преждевременное абстрагирование ничем не лучше преждевременной оптимизации. Как организована эта книга Читатели, на которых рассчитана эта книги, без труда смогут начать чтение с любой главы. Но каждая из шести частей образует книгу в книге. Я предполагал, что главы, составляющие одну часть, будут читаться по порядку. Я старался сначала рассказывать о том, что уже есть, а лишь затем – о том, как создавать что-то свое. Например, в главе 2 из части II рассматриваются готовые типы последовательностей, в том числе не слишком хорошо известные, например Предисловие 19 collections.deque. О создании пользовательских последовательностей речь пойдет только в части IV, где мы также узнаем об использовании абстрактных базовых классов (abstract base classes – ABC) из модуля collections.abc. Создание собст­ венного ABC обсуждается еще позже, поскольку я считаю, что сначала нужно освоиться с использованием ABC, а уж потом писать свои. У такого подхода несколько достоинств. Прежде всего, зная, что есть в вашем распоряжении, вы не станете заново изобретать велосипед. Мы пользуемся готовыми классами коллекций чаще, чем реализуем собственные, и можем уделить больше внимания нетривиальным способам работы с имеющимися средствами, отложив на потом разговор о разработке новых. И мы скорее унаследуем существующему абстрактному базовому классу, чем будем создавать новый с нуля. Наконец, я полагаю, что понять абстракцию проще после того, как видел ее в дейст­ вии. Недостаток же такой стратегии в том, что главы изобилуют ссылками на более поздние материалы. Надеюсь, узнав, почему я выбрал такой путь, вам будет проще с этим смириться. Ниже описаны основные темы, рассматриваемые в каждой части книги. Часть I Содержит всего одну главу, посвященную модели данных в Python, где объясняется ключевая роль специальных методов (например, __repr__) для обеспечения единообразного поведения объектов любого типа – в языке, заслуженно считающемся образцом единообразия. Осмысление различных граней модели данных – сквозная тема книги, но именно в главе 1 дается общий обзор. Часть II В главах из этой части рассматриваются типы коллекций: последовательности, отображения и множества, а также сравниваются типы str и bytes. Это вещи, которые радостно приветствовали пользователи Python 3 и которых отчаянно не хватает пользователям Python 2, еще не модернизировавшим свой код. Основная цель – напомнить, что уже имеется, и объяснить некоторые особенности поведения, которые могут оказаться неожиданными, например, изменение порядка ключей словаря dict в то время, когда в нем никто ничего не ищет, или подводные камни, связанные с зависящей от локали сортировкой строки Unicode. Во имя достижения этой цели изложение временами становится широким и высокоуровневым (например, во время знакомства с многочисленными типами последовательностей и отображений), а временами – углубленным (например, при описании деталей хэш-таблиц, лежащих в основе типов dict и set). Часть III Здесь речь пойдет о функциях, как полноправных объектах языка: что под этим понимается, как это отражается на некоторых популярных паттернах 20 Предисловие проектирования и как реализовать декораторы функций с помощью замыканий. Рассматриваются также следующие вопросы: общая идея вызываемых объектов, атрибуты функций, интроспекция, аннотации параметров и появившееся в Python 3 объявление nonlocal. Часть IV Теперь наше внимание перемещается на создание классов. В части II несколько раз встречалось объявление class, а в части IV представлены многочисленные классы. Как и в любом объектно-ориентированном (ОО) языке, в Python имеется свой набор средств, какие-то из них, возможно, присутствовали в языке, с которого вы и я начинали изучение программирование на основе классов, а какие-то – нет. В главах из этой части объясняется, как работает механизм ссылок, что на самом деле означает изменчивость, как устроен жизненный цикл объектов, как создать свою коллекцию или абстрактный базовый класс, как справиться с множественным наследованием и как реализовать перегрузку операторов (если это имеет смысл). Часть V Эта часть посвящена языковым конструкциям и библиотекам, выходящим за рамки последовательного потока управления с его условными выражениями, циклами и подпрограммами. Сначала мы рассматриваем генераторы, затем – контекстные менеджеры и сопрограммы, в том числе трудную для понимания, но исключительно полезную конструкцию yield from. Часть V заканчивается высокоуровневым введением в современные средства распараллеливания, реализованные в Python в виде модуля collections.futures (потоки и процессы, представленные под маской будущих объектов), и событийно-ориентированного ввода-вывода посредством asyncio (будущие объекты, надстроенные над сопрограммами и yield from). Часть VI Эта часть начинается с обзора способов построения классов с динамически создаваемыми атрибутами для обработки слабоструктурированных данных, например в формате JSON. Затем мы рассматриваем знакомый механизм свойств, после чего переходим к низкоуровневым деталям доступа к атрибутам объекта с помощью дескрипторов. Объясняется связь между функциями, методами и дескрипторами. На примере приведенной здесь пошаговой реализации библиотеки контроля полей мы вскрываем тонкие нюансы, которые делают необходимым применение рассмотренных в этой главе продвинутых инструментов: декораторов классов и метаклассов. Практикум Часто для исследования языка и библиотек мы будем пользоваться интерактивной оболочкой Python. Я считаю важным всячески подчеркивать удобство Предисловие 21 этого средства для обучения. Особенно это относится к читателям, привыкших к статическим компилируемым языкам, в которых нет цикла чтения-вычисленияпечати (read-eval-print#loop – REPL). Один из стандартных пакетов тестирования для Python, doctest (https:// docs.python.org/3/library/doctest.html), работает следующим образом: имитирует сеансы оболочки и проверяет, что результат вычисления выражения совпадает с заданным. Я использовал doctest для проверки большей части приведенного в книге кода, включая листинги сеансов оболочки. Для чтения книги ни применять, ни даже знать о пакете doctest не обязательно: основная характеристика doctest-скриптов состоит в том, что они выглядят, как копии интерактивных сеансов оболочки Python, поэтому вы можете сами выполнить весь демонстрационный код. Иногда я буду объяснять, чего мы хотим добиться, демонстрируя doctestскрипт раньше кода, который заставляет его выполниться успешно. Если сначала отчетливо представить себе, что необходимо сделать, а только потом задумываться о том, как это сделать, то структура кода заметно улучшится. Написание тестов раньше кода – основа методологии разработки через тестирование (TDD); мне кажется, что и для преподавания это полезно. Если вы незнакомы с doctest, загляните в документацию (https://docs.python.org/3/library/doctest.html) и в репозиторий исходного кода к этой книге (https://github.com/fluentpython/ example-code). Вы обнаружите, что для проверки правильности большей части кода в книге достаточно ввести команду python3 -m doctest example_script.py в оболочке ОС. Как производился хронометраж В этой книге иногда приводятся результаты простого хронометража. Тесты производились на одном из двух ноутбуков, которыми я пользовался для написания книги: MacBook Pro 13" 2011 года с процессором Intel Core i7 2.7 ГГц, памятью 8 ГБ и вращающимся жестким диском MacBook Air 13" 2014 года с процессором Intel Core i5 1.4 ГГц, памятью 4 ГБ и SSD-диском. MacBook Air оснащен менее быстрым процессором и располагает меньшим объемом оперативной памяти, зато эта память быстрее (1600 МГц против 1333 МГц), а SSDдиск гораздо быстрее вращающегося. Не могу сказать, какая машина быстрее для повседневной работы. Поговорим: мое личное мнение Я использую, преподаю и принимаю участие в обсуждениях Python с 1998 года и обожаю изучать и сравнивать разные языки программирования, их дизайн и теоретические основания. В конце некоторых глав имеются врезки «Поговорим», где излагается моя личная точка зрения на Python и другие языки. Если вас такие обсуждения не интересуют, можете спокойно пропускать их. Приведенные в них сведения всегда факультативны. 22 Предисловие Терминология Python Я стремился написать книгу не только о самом языке Python, но и о сложившейся вокруг него культуре. За 20 лет существования сообщество пользователей Python выработало собственный профессиональный жаргон и акронимы. В конце книги есть раздел «Терминология Python», в котором перечислены термины, имеющие специальный смысл для питонистов. Использованная версия Python Весь приведенный в книге код тестировался для версии Python 3.4, точнее CPython 3.4, – самой распространенной реализации Python, написанной на C. С одним исключением: в разделе «Новый инфиксный оператор @ в Python 3.5» описывается оператор @, который поддерживается только в версии Python 3.5. Почти весь код должен работать для любого интерпретатора, совместимого с Python 3.x, в том числе PyPy3 2.4.0, совместимого с Python 3.2.5. Из существенных исключений упомяну конструкцию yield from и модуль asyncio, появившиеся только в версии 3.3. По большей части, код должен работать и в Python 2.7 с мелкими изменениями за исключением примеров в главе 4, относящихся к Unicode, и уже упомянутой функциональности, отсутствующей в версиях младше 3.3. Графические выделения В книге применяются следующие графические выделения: Курсив Новые термины, URL-адреса, адреса электронной почты, имена и расширения файлов. Моноширинный Листинги программ, а также элементы кода в основном тексте: имена переменных и функций, базы данных, типы данных, переменные окружения, предложения и ключевые слова языка. Отмечу, что когда внутри элемента, набранного моноширинным шрифтом, оказывается разрыв строки, дефис не добавляется, поскольку он мог бы быть ошибочно принят за часть элемента. Моноширинный полужирный Команды или иной текст, который пользователь должен вводить буквально. Моноширинный курсив Текст, вместо которого следует подставить значения, заданные пользователем или определяемые контекстом. 23 Предисловие Так обозначается совет или рекомендация. Так обозначается замечание общего характера. Так обозначается предупреждение или предостережение. О примерах кода Все скрипты и большая часть приведенных в книге фрагментов кода имеются в репозитории на GitHub по адресу (https://github.com/fluentpython/example-code). Мы высоко ценим, хотя и не требуем, ссылки на наши издания. В ссылке обычно указываются название книги, имя автора, издательство и ISBN, например: «Fluent Python by Luciano Ramalho (O'Reilly). Copyright 2015 Luciano Ramalho, 978-1-491-94600-8». Как с нами связаться Вопросы и замечания по поводу этой книги отправляйте в издательство: O'Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (в США и Канаде) 707-829-0515 (международный или местный) 707-829-0104 (факс) Для этой книги имеется веб-страница, на которой публикуются списки замеченных ошибок, примеры и прочая дополнительная информация. Адрес страницы: http://bit.ly/fluent-python. Замечания и вопросы технического характера следует отправлять по адресу bookquestions@oreilly.com. Дополнительную информацию о наших книгах, конференциях и новостях вы можете найти на нашем сайте по адресу http://www.oreilly.com. Читайте нас на Facebook: http://facebook.com/oreilly. Следите за нашей лентой в Twitter: http://twitter.com/oreillymedia. Смотрите нас на YouTube: http://www.youtube.com/oreillymedia. ЧАСТЬ I Пролог Глава 1. Модель данных в языке Python У Гвидо поразительное эстетическое чувство дизайна языка. Я встречал многих замечательных проектировщиков языков программирования, создававших теоретически красивые языки, которыми никто никогда не пользовался, а Гвидо – один из тех редких людей, которые могут создать язык, немного недотягивающий до теоретической красоты, зато такой, что писать на нем программы в радость.1 – Джим Хагьюнин, автор Jython, соавторAspectJ, архитектор .Net DLR Одно из лучших качеств Python – его согласованность. Немного поработав с этим языком, вы уже сможете строить обоснованные и правильные предположения о еще незнакомых средствах. Однако тем, кто раньше учил другой объектно-ориентированный язык, может показаться странным синтаксис len(collection) вместо collection.len(). Это кажущаяся несообразность – лишь верхушка айсберга, и, если ее правильно понять, то она станет ключом к тому, что мы называем «питонизмами». А сам айсберг называется моделью данных в Python и описывает API, следуя которому можно согласовать свои объекты с самыми идиоматичными средствами языка. Можно считать, что модель данных описывает Python как каркас. Она формализует различные структурные блоки языка, в частности, последовательности, итераторы, функции, классы, контекстные менеджеры и т. д. При программировании в любом каркасе вы тратите большую часть времени на реализацию вызываемых каркасом методов. То же самое справедливо для модели данных Python. Интерпретатор Python вызывает специальные методы для выполнения базовых операций над объектами, часто такие вызовы происходят, когда встречается некая синтаксическая конструкция. Имена специальных методов начинаются и заканчиваются двумя знаками подчеркивания (например, __getitem__). Так, за синтаксической конструкцией obj[key] стоит специальный 1 История Jython (http://hugunin.net/story_of_jython.html), изложенная в предисловии к книге Samuele Pedroni and Noel Rappin «Jython Essentials» (O'Reilly). Колода карт на Python 29 метод __getitem__. Для вычисления выражения my_collection[key] интерпретатор вызывает метод my_collection.__getitem__(key). Благодаря специальным методам объекты могут реализовывать, поддерживать и взаимодействовать с базовыми конструкциями языка, а именно: • итерирование; • коллекции; • доступ к атрибутам; • перегрузка операторов; • вызов функций и методов; • создание и уничтожение объектов; • представление и форматирование строк; • управляемые контексты (т. е. блоки with). Магические и dunder-методы На жаргоне специальные методы обычно называют магическими, но в применении к конкретным методам, например __getitem__, некоторые разработчики говорят «подчерк-подчерк-getitem» (under-under-getitem), внося тем самым двусмысленность, потому что у конструкции __x имеется другой специальный смысл2. Произносить правильно – «подчерк-подчерк-getitem-подчеркподчерк» – утомительно, поэтому я, следуя своему учителю Стиву Холдену, говорю «dunder-getitem». Все опытные питонисты понимают это сокращение. По этой причине специальные методы иногда называют также dunder-методами3. Колода карт на Python Следующий пример очень прост, однако демонстрирует выгоды от реализации двух специальных методов: __getitem__ и __len__. В примере 1.1 приведен класс, представляющий колоду игральных карт. Пример 1.1. Колода как последовательность карт import collections Card = collections.namedtuple('Card', ['rank', 'suit']) class FrenchDeck: См. раздел «Закрытые и защищенные методы в Python» ниже. Лично я впервые услышал слово «dunder» от Стива Холдена. Википедия (http://bit.ly/1Vm72Mf) приписывает авторство Марку Джонсону и Тиму Хохбергу, которые первыми употребили это слово в письменном ответе на вопрос «Как произнести __ (двойное подчеркивание)?» в списке рассылки python-list 26 сентября 2002 года; ответ Джонсона см. по адресу https://mail.python.org/pipermail/ python-list/2002-September/112991.html. 2 3 30 Глава 1. Модель данных в языке Python ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = 'spades diamonds clubs hearts'.split() def __init__(self): self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks] def __len__(self): return len(self._cards) def __getitem__(self, position): return self._cards[position] Прежде всего, отметим использование collections.namedtuple для конструирования простого класса, представляющего одну карту. Начиная с версии Python 2.6, класс namedtuple можно использовать для построения классов, содержащих только атрибуты и никаких методов, как, например, запись базы данных. В данном примере мы воспользовались им для создания простого представления игральной карты, что продемонстрировано в следующем сеансе оболочки: >>> beer_card = Card('7', 'diamonds') >>> beer_card Card(rank='7', suit='diamonds') Но изюминка примера – класс FrenchDeck. Совсем короткий, он таит в себе немало интересного. Во-первых, как и для любой стандартной коллекции в Python, для колоды можно вызвать функцию len(), которая вернет количество карт в ней: >>> deck = FrenchDeck() >>> len(deck) 52 Получение карты из колоды, например первой или последней, не должно быть сложнее обращения deck[0] или deck[-1], и именно это обеспечивает метод __getitem__: >>> deck[0] Card(rank='2', suit='spades') >>> deck[-1] Card(rank='A', suit='hearts') Нужно ли создавать метод для выбора случайной карты? Необязательно. В Python уже есть функция выборки случайного элемента последовательности: random.choice. Достаточно вызвать ее для экземпляра колоды: >>> from random import choice >>> choice(deck) Card(rank='3', suit='hearts') >>> choice(deck) Card(rank='K', suit='spades') >>> choice(deck) Card(rank='2', suit='clubs') 31 Колода карт на Python Мы только что видели два преимущества от использования специальных методов для работы с моделью данных. • Пользователям вашего класса нет нужды запоминать нестандартные имена методов для выполнения стандартных операций («Как мне получить количество элементов? То ли .size(), то ли .length(), то ли еще как-то»). • Проще воспользоваться богатством стандартной библиотеки Python (например, функцией random.choice), чем изобретать велосипед. Но это еще не все. Поскольку метод __getitem__ делегирует выполнение оператору [] объекта self._cards, колода автоматически поддерживает срезы. Вот как можно посмотреть три верхние карты в неперетасованной колоде, а затем выбрать только тузы, начав с элемента, имеющего индекс 12, и пропуская по 13 карт: >>> deck[:3] [Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')] >>> deck[12::13] [Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')] Стоило нам реализовать специальный метод допускать итерирование: __getitem__, как колода стала >>> for card in deck: # doctest: +ELLIPSIS ... print(card) Card(rank='2', suit='spades') Card(rank='3', suit='spades') Card(rank='4', suit='spades') ... Итерировать можно и в обратном порядке: >>> for card in reversed(deck): # doctest: +ELLIPSIS ... print(card) Card(rank='A', suit='hearts') Card(rank='K', suit='hearts') Card(rank='Q', suit='hearts') ... Многоточие в doctest-скриптах Всюду, где возможно, листинги сеансов оболочки извлекались из doctest-скриптов, чтобы гарантировать точность. Если вывод слишком длинный, то опущенная часть помечается многоточием, как в последней строке показанного выше кода. В таких случаях мы используем директиву # doctest: +ELLIPSIS, чтобы doctestскрипт завершился успешно. Если вы будете вводить эти примеры в интерактивной оболочке, можете вообще опускать директивы doctest. 32 Глава 1. Модель данных в языке Python Итерирование часто подразумевается неявно. Если в коллекции отсутствует метод __contains__, то оператор in производит последовательный просмотр. Конкретный пример – в классе FrenchDeck оператор in работает, потому что этот класс итерируемый. Проверим: >>> Card('Q', 'hearts') in deck True >>> Card('7', 'beasts') in deck False А как насчет сортировки? Обычно карты ранжируются по достоинству (тузы – самые старшие), а затем по масти в порядке пики (старшая масть), черви, бубны и трефы (младшая масть). Приведенная ниже функция ранжирует карты, следуя этому правилу: 0 означает двойку треф, а 21 – туза пик. suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0) def spades_high(card): rank_value = FrenchDeck.ranks.index(card.rank) return rank_value * len(suit_values) + suit_values[card.suit] С помощью функции порядке возрастания: spades_high мы теперь можем расположить колоду в >>> for card in sorted(deck, key=spades_high): # doctest: +ELLIPSIS ... print(card) Card(rank='2', suit='clubs') Card(rank='2', suit='diamonds') Card(rank='2', suit='hearts') ... (46 карт опущено) Card(rank='A', suit='diamonds') Card(rank='A', suit='hearts') Card(rank='A', suit='spades') Хотя класс FrenchDeck неявно наследует object4, его функциональность не наследуется, а является следствием использования модели данных и композиции. Вследствие реализации специальных методов __len__ и __getitem__ класс FrenchDeck ведет себя, как стандартная последовательность, и позволяет использовать базовые средства языка (например, итерирование и получение среза), а также функции reversed и sorted. Благодаря композиции реализации методов __len__ и __getitem__ могут перепоручать работу объекту self._cards класса list. А как насчет тасования? В текущей реализации объект класса FrenchDeck нельзя перетасовать, потому что он неизменяемый: ни карты, ни их позиции невозможно изменить, не нарушая инкапсуляцию (т. е. манипулируя атрибутом _cards непосредственно). В главе 11 мы исправим это, добавив однострочный метод __setitem__. 4 В Python 2 необходимо было бы явно написать FrenchDeck(object), а в Python 3 это подразумевается по умолчанию. Эмуляция числовых типов 33 Как используются специальные методы Говоря о специальных методах, нужно все время помнить, что они предназначены для вызова интерпретатором, а не вами. Вы пишете не my_object.__len__(), а len(my_object), и, если my_object – экземпляр определенного пользователем класса, то Python вызовет реализованный вами метод экземпляра __len__. Однако для встроенных классов, например list, str, bytearray и т. д., интерпретатор поступает проще: реализация функции len() в CPython возвращает значение поля ob_size C-структуры PyVarObject, которой представляется любой встроенный объект в памяти. Это гораздо быстрее, чем вызов метода. Как правило, специальный метод вызывается неявно. Например, предложение for i in x: подразумевает вызов функции iter(x), которая, в свою очередь, может вызывать метод x.__iter__(), если он реализован. Обычно в вашей программе не должно быть много прямых обращений к специальным методам. Если вы не пользуетесь метапрограммированием, то чаще будете реализовывать специальные методы, чем явно вызывать их. Единственный специальный метод, которые регулярно вызывается из пользовательского кода напрямую, – __init__, он служит для инициализации суперкласса из вашей реализации __init__. Если необходимо обратиться к специальному методу, то обычно лучше вызвать соответствующую встроенную функцию (например, len, iter, str и т. д.). Она вызывает нужный специальный метод и нередко предоставляет дополнительный сервис. К тому же для встроенных типов это быстрее, чем вызов метода. См. раздел «Познакомимся с функцией iter поближе» главы 14. Старайтесь не создавать собственные атрибуты с именами вида __foo__, потому что в будущем подобные имена могут получить специальный смысл, даже если в текущей версии это не так. Эмуляция числовых типов Несколько специальных методов позволяют объектам иметь операторы, например +. Подробно мы рассмотрим этот вопрос в главе 13, а пока проиллюстрируем использование таких методов на еще одном простом примере. Мы реализуем класс для представления двумерных векторов, обычных евклидовых векторов, применяемых в математике и физике (рис. 1.1). Для представления двумерных векторов можно использовать встроенный класс complex, но наш класс допускает обобщение на n-мерные векторы. Мы займемся этим в главе 14. 34 Глава 1. Модель данных в языке Python Рис. 1.1. Пример сложения двумерных векторов: Vector(2, 4) + Vector(2, 1) = Vector(4, 5) Для начала спроектируем API класса, написав имитацию сеанса оболочки, которая впоследствии станет doctest-скриптом. В следующем фрагменте тестируется сложение векторов, изображенное на рис. 1.1. >>> v1 = Vector(2, 4) >>> v2 = Vector(2, 1) >>> v1 + v2 Vector(4, 5) Отметим, что оператор + порождает результат типа Vector, который отображается в оболочке интуитивно понятным образом. Встроенная функция abs возвращает абсолютное значение вещественного числа – целого или с плавающей точкой – и модуль числа типа complex, поэтому для единообразия наш API также использует функцию abs для вычисления модуля вектора: >>> v = Vector(3, 4) >>> abs(v) 5.0 Мы можем также реализовать оператор *, выполняющий умножение на скаляр (т. е. умножение вектора на число, в результате которого получается новый вектор с тем же направлением и умноженным на данное число модулем): >>> v * 3 Vector(9, 12) >>> abs(v * 3) 15.0 Строковое представление 35 В примере 1.2 приведен класс Vector, реализующий описанные операции с помощью специальных методов __repr__, __abs__, __add__ и __mul__. Пример 1.2. Простой класс двумерного вектора from math import hypot class Vector: def __init__(self, x=0, y=0): self.x = x self.y = y def __repr__(self): return 'Vector(%r, %r)' % (self.x, self.y) def __abs__(self): return hypot(self.x, self.y) def __bool__(self): return bool(abs(self)) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Vector(x, y) def __mul__(self, scalar): return Vector(self.x * scalar, self.y * scalar) Отметим, что ни один из реализованных нами специальных методов (кроме не вызывается напрямую внутри самого класса или при типичном использовании класса, показанном в листингах сеансов оболочки. Как уже было сказано, чаще всего специальные методы вызывает интерпретатор Python. В следующих разделах мы обсудим, как писать каждый специальный метод. __init__) Строковое представление Специальный метод __repr__ вызывается встроенной функцией repr для получения строкового представления объекта. Если бы мы не реализовали метод __repr__, то объект класса Vector был бы представлен в оболочке строкой вида <Vector object at 0x10e100070>. Интерактивная оболочка и отладчик вызывают функцию repr, передавая ей результат вычисления выражения. То же самое происходит при обработке спецификатора %r в случае классического форматирования с помощью оператора % и при обработке поля преобразования !r в новом синтаксисе форматной строки (http:// bit.ly/1Vm7gD1), применяемом в методе str.format. 36 Глава 1. Модель данных в языке Python Я в этой книге использую оператор % и метод str.format, как и большая часть сообщества Python. Мне очень нравится более мощный метод str.format, но я знаю, что многие питонисты предпочитают более простой оператор %, так что в обозримом будущем мы, скорее всего, будем встречать в написанных на Python программах оба варианта. Отметим, что в нашей реализации метода __repr__ мы использовали %r для получения стандартного представления отображаемых атрибутов. Это разумный подход, потому что в нем отчетливо проявляется существенное различие между Vector(1, 2) и Vector('1', '2') – второй вариант в контексте этого примера не заработал бы, потому что аргументами конструктора должны быть числа, а не строки. Строка, возвращаемая методом __repr__, должна быть однозначно определена и по возможности соответствовать коду, необходимому для восстановления объекта. Именно поэтому мы выбрали представление, напоминающее вызов конструктора класса (например, Vector(3, 4)). В отличие от __repr__, метод __str__ вызывается конструктором str() и неявно используется в функции print. Метод __str__ должен возвращать строку, пригодную для показа пользователям. Если вы реализуете только один из этих двух методов, то пусть это будет __repr__, потому что в отсутствие пользовательского метода __str__ интерпретатор Python вызывает __repr__. На сайте Stack Overflow был задан вопрос «Difference between __str__ and __repr__ in Python» (http://bit.ly/1Vm7j1N), ответ на который содержит прекрасные разъяснения Алекса Мартелли и Мартина Питерса. Арифметические операторы В примере 1.2 реализованы два оператора: + и *, чтобы продемонстрировать принципы работы методов __add__ и __mul__. Отметим, что оба метода создают и возвращают новый экземпляр Vector, не модифицируя ни один операнд, – аргументы self и other только читаются. Это ожидаемое поведение инфиксных операторов: создавать новые объекты, не трогая операнды. Я еще вернусь к этому вопросу в главе 13. В примере 1.2 реализовано умножение объекта Vector на число, но не числа на объект Vector, что нарушает свойство коммутативности умножения. В главе 13 мы исправим этот недочет с помощью специального метода __rmul__.