Programming
Python
Forth Edition
Mark Lutz
O REILLY
Программирование
на Python
том I
Четвертое издание
Марк Лутц
Марк Лутц
Программирование на Python, том I, 4-е издание
Перевод А. Киселева
А. Галунов Н. Макарова П. Щеголев Ю. Бочина С. Минин К. Чубаров
Главный редактор
Зав. редакцией
Выпускающий редактор
Редактор
Корректор
Верстка
Лутц М.
Программирование на Python, том I, 4-е издание. - Пер. с англ. - СПб.: Символ-Плюс, 2011. - 992 с., ил.
ISBN 978-5-93286-210-0
Вы овладели основами Python. Что дальше? Эта книга представляет собой подробное руководство по применению этого языка программирования в основных прикладных областях - системном администрировании, создании графических интерфейсов и веб-приложений. Исследуются приемы работы с базами данных, программирования сетевых взаимодействий, создания интерфейсов для сценариев, обработки текста и многие другие.
Издание описывает синтаксис языка и методики разработки, содержит большое количество примеров, иллюстрирующих типичные идиомы программирования и корректное их применение. Кроме того, исследуется эффективность Python в качестве инструмента разработки программного обеспечения, в отличие от просто инструмента «создания сценариев».
В четвертое издание включено описание новых особенностей языка, библиотек и практических приемов программирования для Python 3.X. Примеры, представленные в книге, опробованы под третьей альфа-версией Python 3.2.
Можно смело утверждать, что это обстоятельная и всесторонняя книга предназначена быть первой ступенью на пути овладения мастерством разработки приложений на языке Python.
ISBN 978-5-93286-210-0 ISBN 978-0-596-15810-1 (англ)
© Издательство Символ-Плюс, 2011
Authorized translation of the English edition © 2011 O’Reilly Media Inc. This translation is published and sold by permission of O’Reilly Media Inc., the owner of all rights to publish and sell the same.
Все права на данное издание защищены Законодательством РФ, включая право на полное или частичное воспроизведение в любой форме. Все товарные знаки или зарегистрированные товарные знаки, упоминаемые в настоящем издании, являются собственностью соответствующих фирм.
Издательство «Символ-Плюс». 199034, Санкт-Петербург, 16 линия, 7, тел. (812) 380-5007, www.symbol.ru. Лицензия ЛП N 000054 от 25.12.98. Подписано в печать 31.07.2011. Формат 70x100 1/16.
Печать офсетная. Объем 62 печ. л.
Оглавление
Предисловие...........................................................................15
«А теперь нечто совершенно иное...».......................................15
Об этой книге.......................................................................16
О четвертом издании.............................................................18
Влияние Python 3.X на эту книгу............................................26
Использование примеров из книги..........................................31
Как связаться с издательством O’Reilly....................................33
Типографские соглашения.....................................................34
Благодарности........................................................................35
Об авторе...............................................................................38
Часть I. Начало..........................................................................39
Глава 1. Предварительный обзор.............................................41
«Программирование на Python»: краткий очерк.......................41
Постановка задачи................................................................42
Шаг 1: представление записей................................................43
Списки............................................................................43
Словари ..........................................................................48
Шаг 2: сохранение записей на длительное время.......................54
Текстовые файлы.............................................................55
Модуль pickle...................................................................61
Работа модуля pickle с отдельными записями.......................64
Модуль shelve..................................................................66
Шаг 3: переход к ООП............................................................69
Использование классов .....................................................71
Добавляем поведение........................................................73
Добавляем наследование ...................................................74
Реструктуризация программного кода.................................75
Добавляем возможность сохранения...................................79
Другие разновидности баз данных ......................................81
Шаг 4: добавляем интерфейс командной строки........................83
Шаг 5: добавляем графический интерфейс ...............................86
Основы графических интерфейсов......................................87
ООП при разработке графических интерфейсов.....................89
Получение ввода от пользователя.......................................92
Графический интерфейс к хранилищу.................................94
Шаг 6: добавляем веб-интерфейс...........................................102
Основы CGI....................................................................103
Запуск веб-сервера..........................................................106
Использование строки запроса и модуля urllib....................109
Форматирование текста ответа.........................................110
Веб-интерфейс к хранилищу с данными.............................111
Конец демонстрационного примера.......................................123
Часть II. Системное программирование................................127
Глава 2. Системные инструменты..........................................129
«os.path - дорога к знанию» .................................................129
Зачем здесь нужен Python?..............................................129
В следующих пяти главах................................................130
Знакомство с разработкой системных сценариев.....................132
Системные модули Python...............................................133
Источники документации по модулям...............................134
Постраничный вывод строк документации.........................135
Сценарий постраничного вывода.......................................137
Основы использования строковых методов.........................138
Другие особенности строк в Python 3.X:
Юникод и тип bytes........................................................141
Основы операций с файлами ............................................142
Два способа использования программ ...............................143
Руководства по библиотекам Python..................................144
Коммерческие справочники.............................................145
Модуль sys ........................................................................ 146
Платформы и версии ......................................................146
Путь поиска модулей......................................................146
Таблица загруженных модулей........................................148
Сведения об исключениях ...............................................149
Другие элементы, экспортируемые модулем sys .................150
Модуль os..........................................................................150
Инструменты в модуле os.................................................151
Средства администрирования...........................................152
Константы переносимости ............................................... 153
Основные инструменты os.path ........................................153
Выполнение команд оболочки из сценариев ....................... 156
Другие элементы, экспортируемые модулем os .................. 163
Глава 3. Контекст выполнения сценариев...............................167
«Ваши аргументы, пожалуйста!»..........................................167
Текущий рабочий каталог ...................................................168
Текущий рабочий каталог, файлы и путь поиска модулей____168
Текущий рабочий каталог и командные строки ..................170
Аргументы командной строки .............................................. 171
Анализ аргументов командной строки...............................172
Переменные окружения оболочки.........................................175
Получение значений переменных оболочки........................176
Изменение переменных оболочки.....................................177
Особенности переменных оболочки:
родители, putenv и getenv................................................179
Стандартные потоки ввода-вывода........................................180
Перенаправление потоков ввода-вывода
в файлы и программы .....................................................181
Перенаправление потоков
и взаимодействие с пользователем....................................187
Перенаправление потоков в объекты Python.......................192
Вспомогательные классы io.StringIO и io.BytesIO...............196
Перехват потока stderr....................................................197
Возможность перенаправления с помощью функции print____197
Другие варианты перенаправления:
еще раз об os.popen и subprocess........................................198
Глава 4. Инструменты для работы с файлами и каталогами.... 206
«Как очистить свой жесткий диск за пять простых шагов».......206
Инструменты для работы с файлами ..................................... 206
Модель объекта файла в Python 3.X..................................207
Использование встроенных объектов файлов ...................... 209
Двоичные и текстовые файлы........................................... 220
Низкоуровневые инструменты в модуле os
для работы с файлами ..................................................... 233
Сканеры файлов.............................................................239
Инструменты для работы с каталогами .................................. 243
Обход одного каталога.....................................................243
Обход деревьев каталогов ................................................249
Обработка имен файлов в Юникоде
в версии 3.X: listdir, walk, glob.........................................254
Глава 5. Системные инструменты
параллельного выполнения..................................................258
«Расскажите обезьянам, что им делать» ................................258
Ветвление процессов ........................................................... 260
Комбинация fork/exec.....................................................264
Потоки выполнения............................................................270
Модуль _thread..............................................................274
Модуль threading............................................................ 287
Модуль queue.................................................................293
Графические интерфейсы и потоки выполнения:
предварительное знакомство ............................................ 298
Подробнее о глобальной блокировке
интерпретатора (GIL)......................................................302
Завершение программ ......................................................... 306
Завершение программ средствами модуля sys.....................306
Завершение программ средствами модуля os......................307
Коды завершения команд оболочки...................................308
Код завершения процесса
и совместно используемая информация.............................312
Код завершения потока
и совместно используемая информация.............................314
Взаимодействия между процессами.......................................316
Анонимные каналы........................................................318
Именованные каналы (fifo)..............................................331
Сокеты: первый взгляд .................................................... 335
Сигналы ........................................................................ 340
Пакет multiprocessing.........................................................343
Зачем нужен пакет multiprocessing?.................................. 344
Основы: процессы и блокировки.......................................346
Инструменты IPC: каналы, разделяемая память и очереди ... 349
Запуск независимых программ ......................................... 357
И многое другое..............................................................359
Зачем нужен пакет multiprocessing? Заключение ................ 361
Другие способы запуска программ.........................................362
Семейство функций os.spawn...........................................362
Функция os.startfile в Windows........................................366
Переносимый модуль запуска программ ................................368
Другие системные инструменты............................................ 374
Глава 6. Законченные системные программы........................376
«Ярость поиска».................................................................376
Игра: «Найди самый большой файл Python»...........................377
Сканирование каталога стандартной библиотеки................377
Сканирование дерева каталогов стандартной библиотеки.....378
Сканирование пути поиска модулей..................................379
Сканирование всего компьютера....................................... 382
Вывод имен файлов с символами Юникода.........................387
Разрезание и объединение файлов.........................................390
Разрезание файлов переносимым способом......................... 391
Соединение файлов переносимым образом .........................395
Варианты использования................................................. 399
Создание веб-страниц для переадресации ............................... 403
Файл шаблона страницы .................................................404
Сценарий генератора страниц...........................................405
Сценарий регрессивного тестирования ................................... 408
Запускаем тестирование..................................................411
Копирование деревьев каталогов...........................................417
Сравнение деревьев каталогов ..............................................422
Поиск расхождений между каталогами.............................422
Поиск различий между деревьями....................................425
Запускаем сценарий........................................................428
Проверка резервных копий..............................................431
Отчет о различиях и другие идеи ...................................... 433
Поиск в деревьях каталогов..................................................435
grep, glob и find..............................................................436
Создание собственного модуля find...................................437
Удаление файлов с байт-кодом .........................................442
Visitor: обход каталогов «++»...............................................448
Редактирование файлов в деревьях каталогов (Visitor).........454
Глобальная замена в деревьях каталогов (Visitor) ...............456
Подсчет строк исходного программного кода (Visitor)..........458
Копирование деревьев каталогов
с помощью классов (Visitor).............................................460
Другие примеры обходчиков (внешние).............................462
Проигрывание медиафайлов................................................. 464
Модуль webbrowser.........................................................468
Модуль mimetypes..........................................................470
Запускаем сценарий........................................................473
Автоматизированный запуск программ (внешние примеры) ..... 473
Часть III. Программирование графических интерфейсов .... 477
Глава 7. Графические интерфейсы пользователя....................479
«Я здесь, я смотрю на тебя, детка» ........................................479
Темы программирования GUI...........................................479
Запуск примеров ............................................................ 481
Различные возможности создания GUI в Python......................483
Обзор tkinter......................................................................490
Практические преимущества tkinter ................................490
Документация tkinter ..................................................... 492
Расширения для tkinter...................................................492
Структура tkinter...........................................................495
Взбираясь по кривой обучения
программированию графических интерфейсов ........................ 497
«Hello World» в четыре строки (или меньше)......................497
Основы использования tkinter..........................................498
Создание виджетов ......................................................... 499
Менеджеры компоновки .................................................. 500
Запуск программ с графическим интерфейсом....................501
Альтернативные приемы использования tkinter ................. 502
Основы изменения размеров виджетов............................... 504
Настройка параметров графического элемента
и заголовка окна............................................................506
Еще одна версия в память о былых временах......................508
Добавление виджетов без их сохранения ............................ 508
Добавление кнопок и обработчиков.......................................511
Еще раз об изменении размеров виджетов: растягивание......512
Добавление пользовательских обработчиков...........................514
lambda-выражения как обработчики событий.....................515
Отложенные вызовы с применением
инструкций lambda и ссылок на объекты...........................516
Проблемы с областями видимости обработчиков.................518
Связанные методы как обработчики событий......................525
Объекты вызываемых классов как обработчики событий.....527
Другие протоколы обратного вызова в tkinter.....................528
Связывание событий.......................................................529
Добавление нескольких виджетов.........................................530
Еще раз об изменении размеров: обрезание.........................531
Прикрепление виджетов к фреймам..................................532
Порядок компоновки и прикрепление к сторонам ............... 533
Снова о параметрах expand и fill компоновки.....................534
Использование якорей вместо растягивания....................... 536
Настройка виджетов с помощью классов................................537
Стандартизация поведения и внешнего вида.......................538
Повторно используемые компоненты и классы........................ 540
Прикрепление классов компонентов ................................. 542
Расширение классов компонентов..................................... 544
Автономные классы-контейнеры ...................................... 546
Завершение начального обучения ......................................... 549
Соответствие между Python/tkinter и Tcl/Tk..........................551
Глава 8. Экскурсия по tkinter, часть 1......................................553
«Виджеты, гаджеты,
графические интерфейсы... Бог мой!» ....................................553
Темы этой главы.................................................................554
Настройка внешнего вида виджетов......................................554
Окна верхнего уровня..........................................................558
Виджеты Toplevel и Tk....................................................560
Протоколы окна верхнего уровня......................................561
Диалоги ............................................................................ 566
Стандартные (типичные) диалоги.....................................567
Модуль диалогов в старом стиле.......................................580
Пользовательские диалоги............................................... 581
Привязка событий..............................................................585
Другие события, доступные с помощью метода bind.............590
Виджеты Message и Entry....................................................592
Message ......................................................................... 592
Entry ............................................................................ 593
Компоновка элементов ввода в формах..............................595
«Переменные» tkinter и альтернативные способы
компоновки форм...........................................................599
Флажки, переключатели и ползунки ..................................... 602
Флажки ........................................................................ 602
Переключатели..............................................................607
Ползунки......................................................................614
Три способа использования графических интерфейсов.............618
Прикрепление к фреймам................................................619
Независимые окна .......................................................... 624
Запуск программ............................................................626
Изображения.................................................................633
Развлечения с кнопками и картинками ............................. 637
Отображение и обработка изображений с помощью PIL............641
Основы PIL....................................................................641
Отображение других типов графических
изображений с помощью PIL ............................................ 643
Отображение всех изображений в каталоге.........................645
Создание миниатюр изображений
с помощью пакета PIL.....................................................647
Глава 9. Экскурсия по tkinter, часть 2......................................659
«Меню дня: Spam, Spam и еще раз Spam» ...............................659
Меню................................................................................660
Меню окон верхнего уровня ............................................. 660
Меню на основе виджетов Frame и Menubutton...................665
Окна с меню и панелью инструментов................................670
Виджеты Listbox и Scrollbar.................................................676
Программирование виджетов списков ............................... 678
Программирование полос прокрутки................................. 680
Компоновка полос прокрутки...........................................681
Виджет Text.......................................................................683
Программирование виджета Text......................................685
Операции редактирования текста.....................................689
Юникод и виджет Text....................................................695
Более сложные операции с текстом и тегами ......................707
Виджет Canvas...................................................................709
Базовые операции с виджетом Canvas................................710
Программирование виджета Canvas..................................711
Прокрутка холстов.........................................................715
Холсты с поддержкой прокрутки
и миниатюр изображений................................................718
События холстов ............................................................ 722
Сетки................................................................................726
В чем преимущества размещения по сетке? .......................727
Основы работы с сеткой: еще раз о формах ввода.................728
Сравнение методов grid и pack..........................................729
Сочетание grid и pack......................................................731
Реализация возможности растягивания виджетов,
размещаемых по сетке..................................................... 734
Создание крупных таблиц с помощью grid ......................... 738
Инструменты синхронизации,
потоки выполнения и анимация............................................ 747
Использование потоков выполнения
в графических интерфейсах tkinter...................................750
Использование метода after.............................................752
Простые приемы воспроизведения анимации ..................... 755
Другие темы, связанные с анимацией ................................ 762
Конец экскурсии ................................................................ 764
Другие виджеты и их параметры ...................................... 764
Глава 10. Приемы программирования
графических интерфейсов....................................................766
«Создание улучшенной мышеловки».....................................766
GuiMixin: универсальные
подмешиваемые классы ....................................................... 767
Функции создания виджетов............................................ 768
Вспомогательные подмешиваемые классы ......................... 769
GuiMaker: автоматизация создания меню
и панелей инструментов.......................................................773
Протоколы подклассов....................................................778
Классы GuiMaker...........................................................779
Программный код самотестирования GuiMaker..................779
BigGui: клиентская демонстрационная программа .............. 781
ShellGui: графические интерфейсы
к инструментам командной строки........................................785
Обобщенный графический интерфейс
инструментов оболочки...................................................785
Классы наборов утилит....................................................788
Добавление графических интерфейсов
к инструментам командной строки ...................................789
GuiStreams: перенаправление
потоков данных в виджеты................................................... 797
Использование перенаправления
сценариев архивирования ...............................................802
Динамическая перезагрузка обработчиков............................. 803
Обертывание интерфейсов окон верхнего уровня.....................805
Графические интерфейсы, потоки выполнения и очереди.........810
Помещение данных в очередь...........................................813
Помещение обработчиков в очередь...................................817
Другие способы добавления GUI
к сценариям командной строки.............................................825
Вывод окон графического интерфейса по требованию..........826
Реализация графического интерфейса в виде отдельной
программы: сокеты (вторая встреча) .................................830
Реализация графического интерфейса в виде
отдельной программы: каналы.........................................835
Запускающие программы PyDemos и PyGadgets......................845
Панель запуска PyDemos.................................................846
Панель запуска PyGadgets...............................................852
Глава 11. Примеры законченных программ
с графическим интерфейсом.................................................857
«Python, открытое программное обеспечение и Camaro»...........857
Примеры в других главах................................................858
Стратегия данной главы..................................................859
PyEdit: программа/объект текстового редактора.....................862
Запуск PyEdit ................................................................ 863
Изменения в версии PyEdit 2.0 (третье издание)..................872
Изменения в версии PyEdit 2.1 (четвертое издание) ............874
Исходный программный код PyEdit..................................888
PyPhoto: программа просмотра и изменения
размеров изображений........................................................917
Запуск PyPhoto..............................................................918
Исходный программный код PyPhoto................................922
PyView: слайд-шоу для изображений и примечаний................929
Запуск PyView...............................................................929
Исходный программный код PyView.................................935
PyDraw: рисование и перемещение графики ........................... 941
Запуск PyDraw ............................................................... 941
Исходный программный код PyDraw.................................943
PyClock: виджет аналоговых/цифровых часов........................951
Краткий урок геометрии..................................................951
Запуск PyClock...............................................................957
Исходный программный код PyClock................................961
PyToe: виджет игры в крестики-нолики.................................969
Запуск PyToe.................................................................969
Исходный программный код PyToe (внешний) ...................971
Что дальше........................................................................974
Алфавитный указатель.........................................................976
Предисловие
«А теперь нечто совершенно иное...»
В этой книге исследуются способы применения языка программирования Python в типичных прикладных областях и в реально возникающих задачах. Эта книга рассказывает, что можно делать с языком Python после того, как вы овладели его основами.
Эта книга предполагает, что читатель еще только начинает знакомиться с рассматриваемыми в книге прикладными областями - графическими интерфейсами, Интернетом, базами данных, системным программированием и так далее, - и представляет каждую из них, начиная с самых азов, выполняя роль учебника. Попутно книга ставит своей целью познакомить читателя с часто используемыми инструментами и библиотеками, но не с основами языка. Таким образом, данная книга является ресурсом, позволяющим читателю получить более глубокое понимание роли языка Python в практике программирования.
Дополнительно в этой книге исследуется пригодность языка Python на роль инструмента разработки программного обеспечения, в отличие от просто инструмента «создания сценариев». Многие примеры, представленные в этой книге, подобраны в соответствии с этой целью - среди них вы найдете примеры постепенной разработки клиентов электронной почты, опирающиеся на тысячи строк программного кода. Создание подобных крупномасштабных приложений всегда будет непростым делом, но мы покажем, насколько быстрее и проще создаются такие приложения, когда они разрабатываются на языке Python.
Это четвертое издание было дополнено представлением новых особенностей языка, библиотек и практических приемов программирования для Python 3.X. В частности, примеры, представленные в книге, выполняются под управлением интерпретатора версии Python 3.1 - наиболее свежей версии Python на момент написания этих строк. Непосредственно перед публикацией книги все основные примеры были опробованы под третьей альфа-версией Python 3.2, но вообще говоря, они должны сохранить свою работоспособность при использовании любой версии Python из линейки 3.X. Кроме того, это издание было реорганизовано с целью упорядочить прежний материал и добавить описание новых инструментов и тем.
Поскольку среди читателей этой книги будут и те, кому в руки первым попало это издание, и те, кто знаком с предыдущими изданиями, я хочу в этом предисловии более подробно остановиться на целях и задачах этой книги, прежде чем перейти к программному коду.
Об этой книге
Данная книга является учебником по применению языка Python для решения наиболее типичных задач в различных прикладных областях. В ней рассказывается о применении языка Python в системном администрировании, для создания графических интерфейсов и вебприложений и исследуются приемы программирования сетевых взаимодействий, взаимодействий с базами данных, обработки текста, создания интерфейсов для сценариев и во многих других областях. Несмотря на то, что на протяжении всей книги используется язык Python, тем не менее основное внимание будет уделяться не основам языка, а приемам решения практических задач.
Экосистема этой книги
Диапазон тем, обсуждаемых в этой книге, позволяет ее рассматривать, как второй том двухтомника, который должен быть дополнен третьим томом. Важно помнить, что эта книга описывает особенности разработки приложений и является продолжением книги «Изучаем Python»1, рассматривающей основы языка, знание которых совершенно необходимо для чтения этой книги. Поясним, как связаны эти книги между собой:
• «Изучаем Python» - подробно описывает основы программирования на языке Python. Основное внимание уделяется базовым особенностям языка Python, знание которых является необходимой предпосылкой для чтения этой книги.
• «Программирование на Python» - эта книга охватывает практические приемы программирования на языке Python. Основное внимание в этой книге уделяется библиотекам и инструментам, и предполагается, что читатель уже знаком с основами языка.
• «Python Pocket Reference» - краткий справочник, в котором охватываются некоторые подробности, отсутствующие в данной книге. Этот справочник не может использоваться в качестве учебника, но он позволит вам быстро отыскивать описание тех или иных особенностей.
В некотором смысле, эта книга является аналогом «Изучаем Python», но в ней раскрываются не основы языка, а основы прикладного программирования. Это последовательный учебник, в котором не делается никаких предположений об уровне вашей подготовки, и каждая тема начинает рассматриваться с самых азов. Например, при изучении темы разработки веб-приложений вы приобретете все необходимые знания, которые позволят вам создавать простые веб-сайты, и получите представление о более развитых фреймворках и инструментах, которые пригодятся вам с ростом ваших потребностей. Обсуждение особенностей конструирования графических интерфейсов также идет по нарастающей - от простого к сложному.
Дополнением к этой книге может служить книга «Python Pocket Reference» (карманный справочник по языку Python), где предоставляется дополнительная информация о некоторых особенностях, не рассматриваемых в данной книге, и которая может служить отличным справочником. Книга «Python Pocket Reference» является всего лишь справочником, и в ней практически отсутствуют примеры и пояснения, но она может служить отличным дополнением к книгам «Изучаем Python» и «Программирование на Python». Поскольку текущее четвертое издание «Python Pocket Reference» содержит информацию об обеих основных версиях Python, 2.X и 3.X, оно также может использоваться читателями, выполняющими переход между этими двумя версиями Python (подробнее об этом чуть ниже)2.
Чего нет в этой книге
Из-за распределения областей рассмотрения по книгам, о которых упоминалось выше, область применения этой книги имеет следующие ограничения:
• Она не раскрывает основы языка Python
• Она не предназначалась для использования в качестве справочника по особенностям языка
Первый из этих двух пунктов отражает тот факт, что освещение основ языка является исключительной прерогативой книги «Изучаем Python», и если вы совершенно не знакомы с языком Python, я рекомендую сначала прочитать книгу «Изучаем Python», прежде чем приниматься за эту книгу, так как здесь предполагается знание основ языка.
Конечно, некоторые приемы языка демонстрируются в примерах этой книги, а в крупных примерах иллюстрируется, как можно объединять базовые концепции в действующие программы. Особенности объектноориентированного программирования, например, часто лучше всего демонстрировать на примерах крупных программ, которые и будут представлены здесь. Однако формально эта книга предполагает, что вы уже знакомы с основами языка Python в достаточной степени, чтобы понять примеры программного кода. Основное внимание здесь будет уделяться библиотекам и инструментам. Поэтому если программный код, который будет демонстрироваться, покажется вам непонятным, -справляйтесь в других источниках.
Второй из этих двух пунктов отражает тот факт, что за многие годы об этой книге сложились неверные представления (вероятно, стоило назвать эту книгу «Применение Python», будь мы чуть более прозорливы в далеком 1995 году). Я хочу ясно обозначить: эта книга - не справочник. Это учебник. Здесь вы можете найти некоторые подробности, воспользовавшись оглавлением или алфавитным указателем, но данная книга не предназначалась для использования именно в таких целях. Краткий справочник вы найдете в книге под названием «Python Pocket Reference», который вы найдете весьма полезным, как только начнете самостоятельно писать нетривиальный программный код. Существуют и другие источники справочной информации, в том числе другие книги и собственный набор справочных руководств по языку Python. Цель этой книги - постепенное обучение применению языка Python для решения типичных задач, а не подробное описание мельчайших особенностей.
О четвертом издании
Если это первое издание книги, которое вы видите, последние изменения, вероятно, вас будут интересовать меньше всего, поэтому вы можете просто перейти к следующему разделу. Для тех, кто читал предыдущие издания, можно отметить, что четвертое издание этой книги содержит три важных изменения:
• Оно охватывает только Python 3.X.
• Оно было сокращено, чтобы сделать книгу еще направленнее и освободить место для новых тем.
• В него было добавлено обсуждение новых тем и инструментов, появившихся в мире Python.
Первый из этих пунктов является, пожалуй, наиболее важным - это издание опирается на Python 3.X, на стандартную библиотеку для этой версии и на распространенные приемы программирования, используемые его пользователями. Однако чтобы объяснить, как это и два других изменения отразились на данном издании, я должен поведать о некоторых деталях.
Изменения в этом издании
Предыдущие версии книги получили весьма широкое распространение, поэтому ниже я приведу некоторые из наиболее заметных изменений в этом издании:
Существовавший ранее материал был сжат, чтобы освободить место для новых тем
Предыдущее издание книги также имело объем около 1600 страниц, что не позволило выделить достаточно места для рассмотрения новых тем (одна только ориентированность Python 3.X на использование Юникода предполагает массу нового материала). К счастью, недавние изменения в мире Python позволили нам без особого ущерба выкинуть часть существующего материала и освободить место для новых тем.
Глубина обсуждения оставшихся тем при этом не пострадала - эта книга остается такой же основательной, как и прежде. Тем не менее одной из основных задач, стоявших при подготовке этого издания, было не допустить дальнейшего роста его объема, а множество других изменений и сокращений, о которых я упомяну ниже, были сделаны отчасти для того, чтобы включить новые темы.
Рассматривается только Python 3.X
Примеры и пояснения были изменены с учетом того, что теперь эта книга охватывает только версию Python 3.X. Версия Python 2.X больше не поддерживается, за исключением тех особенностей, которые перекочевали из версии 2.X в версию 3.X без изменений. Несмотря на то, что таких особенностей достаточно много, благодаря чему читатели могут использовать версию 2.X, тем не менее формально книга поддерживает только версию 3.X.
В свою очередь это обстоятельство явилось основным фактором, обеспечившим сохранение объема этого издания на прежнем уровне. Ограничившись поддержкой только версии Python 3.X - несовместимой с версией Python 2.X, которую следует рассматривать как будущее языка Python, - нам удалось избежать дублирования описания особенностей, отличающихся в этих двух версиях Python. Такое ограничение поддерживаемых версий особенно важно для такой книги, как эта, где приводится множество расширенных примеров, так как это позволяет демонстрировать примеры только для одной версии.
Для тех, кто по-прежнему пытается удержаться в обоих мирах,
2.X и 3.X, я подробнее расскажу об изменениях в Python 3.X ниже, в этом же предисловии. Самым важным, пожалуй, изменением в версии 3.X, из тех, что описываются в книге, является усовершенствованная поддержка интернационализации в примерах программ PyEdit и PyMailGUI. Несмотря на то, что в версии 2.X также имеется поддержка Юникода, тем не менее усовершенствованная ее реализация в версии 3.X вынуждает заново пересмотреть реализацию подобных систем, прежде ориентированных на работу с кодировкой ASCII.
Включение недавно появившихся библиотек и инструментов
С момента выхода предыдущего издания появилось или получило дальнейшее развитие множество новых библиотек и инструментов, и они также упоминаются здесь. В их число входят новые инструменты стандартной библиотеки языка Python, такие как модули subprocess (рассматривается в главах 2 и 3) и multiprocessing (рассматривается в главе 5), а также новые веб-фреймворки, созданные сторонними разработчиками, и инструменты ORM (Object-Relational Mapping - объектно-реляционное отображение) для работы с базами данных. Большинство из них рассматриваются не очень подробно (многие популярные расширения сами по себе являются сложными системами и гораздо подробнее описаны в соответствующей литературе), но для них дается по крайней мере краткое описание в виде резюме.
Например, новая библиотека виджетов Tk tkinter.ttk рассматривается в главе 7, но весьма кратко. Как правило, в этом издании мы предпочитали упоминать подобные расширения по ходу дела, вместо того чтобы представлять примеры программного кода без внятного пояснения.
Это предисловие было ужато
Я удалил все инструкции по запуску и использованию примеров программ. Поэтому теперь за инструкциями по использованию обращайтесь к файлам README, входящим в состав дистрибутива с комплектом примеров. Кроме того, я убрал большую часть благодарностей, потому что они повторяют благодарности из книги «Изучаем Python», - так как знакомство с книгой «Изучаем Python» теперь считается необходимой предпосылкой, дублирование одного и того же материала здесь ничем не оправдано. Кроме того, было убрано описание содержимого книги - чтобы ознакомиться со структурой книги, обращайтесь к оглавлению.
Была убрана вводная глава с обзором языка Python
Я удалил «организаторскую» главу, присутствовавшую в предыдущем издании, где описывались сильные стороны языка Python, представлялись наиболее видные пользователи, рассматривались различные философии и так далее. Обращение в свою веру играет важную роль в любой сфере, где вопрос «почему» задается менее часто, чем должен бы. В действительности, если бы мастера Python не занимались его популяризацией, все мы, вероятно, использовали бы сейчас Perl или языки командных оболочек!
Однако присутствие здесь такой главы стало совершенно излишним из-за наличия сходной главы в книге «Изучаем Python». Поскольку книга «Изучаем Python» должна предшествовать этой книге, я решил не расходовать книжное пространство на повторную агитацию «Питонистов» («Pythonista»). В этой книге предполагается, что вы уже знаете, почему стоит использовать Python, поэтому мы сразу же перейдем к его применению.
Было убрано заключительное послесловие
Заключительное послесловие к этой книге было написано еще для первого издания, и теперь ему исполнилось уже 15 лет. Естественно, что оно отражает взгляды на Python, в большей степени характерные для того времени. Например, использование языка Python для разработки гибридных приложений казалось более значимым в 1995 году, чем в 2010. В современном, более обширном мире Python большинству пользователей не приходится иметь дело со связанным программным кодом на языке C.
В предыдущих изданиях я добавлял новое послесловие для каждого издания, чтобы уточнить и дополнить идеи, представленные в заключении к книге. Теперь я убрал эти послесловия, заменив их коротким примечанием. Само заключение я решил оставить, потому что оно по-прежнему актуально для многих читателей и имеет некоторую историческую ценность. Да к тому же удачные шутки...
Было убрано вступительное слово
По похожим причинам, представленным в двух предыдущих пунктах, я убрал разделы со вступительным словом к предыдущим изданиям. Те, кому это будет интересно, историческую справку о вкладе Гвидо ван Россума (Guido van Rossum), создателя Python, в развитие языка смогут найти в Интернете. Если вам интересно, как за эти годы изменился язык Python с технической точки зрения, смотрите документ «What’s New» («Что нового»), входящий в состав стандартного комплекта руководств по языку Python (доступен по адресу http://www.python.org/doc и устанавливается вместе с Python в Windows и на других платформах).
Раздел, посвященный интеграции с языком C, был сокращен до одной
главы
Я сократил раздел, посвященный созданию расширений на языке C и встраиванию сценариев на языке Python в программы на языке C, до одной короткой главы в конце части, посвященной инструментальным средствам, где коротко описываются основные понятия, связанные с этой темой. Проблемы связывания программ на языке Python с библиотеками на языке C на сегодняшний день волнуют лишь незначительную часть пользователей, а те, кому эти навыки действительно необходимы, найдут более полный пример интеграции в исходных текстах самого языка Python. Имеющиеся возможности перечислены здесь достаточно полно, но значительный объем программного кода на языке C был вырезан в расчете на то, что более представительные примеры вы найдете в программном коде реализации самого языка Python.
Часть, посвященная системному программированию, была сокращена
и переработана
Прежние две главы с большими примерами использования Python в системном программировании были объединены в одну, более короткую главу с новыми или значительно переработанными примерами. Фактически эта часть (часть II) подверглась самым значительным изменениям. Она включает описание новых инструментов, таких как модули subprocess и multiprocessing, знакомит читателей с сокетами, а кроме того, из нее были удалены устаревшие сведения и примеры, унаследованные из прежних изданий. Честно признаться, несколько примеров работы с файлами были созданы еще в 1990-х годах и оказались сильно устаревшими. Начальная глава в этой части была разбита на две, чтобы упростить чтение материала (описание контекста командной оболочки, включая потоки ввода-вывода, было вынесено в отдельную главу), а несколько листингов крупных программ (включая запускающие сценарии с автоматической настройкой) теперь вынесены за пределы книги и включены в состав дистрибутива с комплектом примеров.
Некоторые крупные примеры были исключены из книги (но остались
в составе дистрибутива с комплектом примеров)
Точно так же из книги были исключены два крупных примера, демонстрирующих создание графического интерфейса, PyTree и PyForm. Однако их обновленная реализация доступна в комплекте примеров. В этом издании вы все еще сможете найти упоминание и описание множества крупных примеров, включая примеры реализации полноценных клиентов электронной почты с графическим и веб-интерфейсом, а также программы для просмотра изображений, калькуляторы, часы, текстовые редакторы с поддержкой Юникода, простые графические редакторы, сценарии регрессивного тестирования и многие другие. Однако, так как программный код примеров не добавляет ничего важного к раскрытию темы и вообще эти примеры предлагались в основном для самостоятельного изучения, - я перевел их в разряд дополнительной информации и исключил их из текста этого издания книги.
Обширная глава с описанием тем, касающихся Интернета, была заменена кратким обзором
Я полностью убрал обширную главу с описанием тем, касающихся Интернета, оставив лишь краткий обзор в начале части (с акцентом на возможностях создания графического интерфейса, который приводится в начале третьей части «Программирование GUI»). Здесь вы найдете все ранее включавшиеся в рассмотрение инструменты, такие как веб-фреймворк ZOPE, объектная модель COM, технологии Windows Active Scripting и ASP, HTMLgen, Python Server Pages (PSP), Jython и уже серьезно устаревшая система Grail. Некоторые из этих инструментов по-прежнему заслуживают положительных оценок, но в этом издании никакие из них не рассматриваются подробно. В обзор были добавлены новые инструменты (включая многие из тех, что перечислены в следующем абзаце), но, опять же, весьма краткие и без примеров программного кода.
Несмотря на все попытки автора угадать направления развития вебтехнологий в будущем, печатное издание не способно полностью соответствовать эволюции сферы развития Интернета. Например, в настоящее время появились веб-фреймворки, такие как Django, Google App Engine, TurboGears, pylons и web2py, соперничающие по своей популярности с ZOPE. Точно так же фреймворк .NET Framework во многих приложениях вытеснил объектную модель Windows COM. Реализация IronPython теперь способна обеспечить такую же тесную интеграцию с .NET, как и Jython с Java. А механизм Active Scripting в значительной степени может быть замещен клиентскими фреймворками, основанными на JavaScript и использующими технологию AJAX, такими как Flex, Silverlight и pyjamas (которые часто называют средствами разработки полнофункциональных вебприложений). Кроме собственно исторической ценности, примеры, ранее представленные в этой категории, не давали возможности изучить описываемые инструменты или хотя бы судить об их достоинствах.
Вместо того чтобы включать в книгу неполное (и практически бесполезное) описание инструментов, которые в течение предполагаемого срока жизни этого издания могут как уйти далеко вперед в своем развитии, так и исчезнуть со сцены, я решил предоставить лишь краткие обзоры наиболее важных тем, касающихся Интернета, и предлагаю читателям самим постараться найти необходимые подробности в Интернете. По сути, основная цель книги, которую вы читаете, состоит в том, чтобы дать углубленные знания об основах Интернета, которые позволят вам воспользоваться более сложными системами, когда вы будете готовы сделать шаг вперед.
Единственное исключение: описание XML, присутствовавшее ранее в этой главе, было дополнено и перемещено в главу, посвященную обработке текста (где оно и должно было бы находиться). Точно так же было сохранено описание объектно-ориентированной базы данных ZODB, поддерживаемой фреймворком ZOPE, хотя и в сильно урезанном виде, чтобы получить возможность добавить описание механизмов ORM, таких как SQLObject и SQLAlchemy (также в краткой форме).
Задействованы, современные инструменты, доступные в версии 3.X
К моменту написания этих строк Python 3.X все еще находился на этапе внедрения, и некоторые из инструментов сторонних разработчиков, которые использовались в примерах в предыдущих изданиях этой книги, по-прежнему доступны только в версиях для Python 2.X. Чтобы обойти этот временный недостаток, я изменил некоторые примеры, задействовав в них альтернативные инструменты, обеспечивающие поддержку версии Python 3.X.
Наиболее заметным в этом смысле является раздел, посвященный базам данных SQL, - теперь в нем вместо интерфейса доступа к серверу MySQL, присутствующего в Python 2.X, используется библиотека SQLite поддержки баз данных, встраиваемых в приложения, которая в версии 3.X стала стандартной частью Python. К счастью, переносимый прикладной интерфейс Python позволяет сценариям взаимодействовать с обоими механизмами практически одинаково, поэтому такое изменение является весьма незначительной жертвой.
Отдельно следует отметить использование расширения PIL для отображения изображений в формате JPEG в части, посвященной созданию графического интерфейса. Это расширение было адаптировано Фредриком Лундом (Fredrik Lundh) для версии Python 3.1 как раз к моменту подготовки этого издания. Когда я сдавал в издательство окончательный вариант рукописи этой книги в июле 2010 года, эта версия расширения официально еще не была выпущена, но она должна была вскоре выйти; поэтому в качестве временной меры заплаты для этой библиотеки, обеспечивающие поддержку Python 3.X, были включены в комплект примеров.
Было исключено описание дополнительных возможностей языка
Все дополнительные особенности языка Python, такие как дескрипторы, свойства, декораторы, метаклассы и поддержка Юникода, являются частью языка Python. Поэтому их описание было перемещено в четвертое издание книги «Изучаем Python». Например, улучшенная поддержка Юникода и ее влияние на приемы работы с файлами, именами файлов, сокетами и со многими другими инструментами обсуждаются в этой книге, но основы Юникода здесь не рассматриваются. Некоторые темы из этой категории определенно имеют прикладной характер (или, по крайней мере, представляют интерес для разработчиков инструментальных средств и архитекторов прикладных интерфейсов), но наличие их описания в книге «Изучаем Python» позволило избежать дальнейшего увеличения объема этой книги. Ищите подробное обсуждение этих тем в книге «Изучаем Python».
Прочие незначительные изменения
Естественно, что попутно было внесено множество мелких изменений. Например, для размещения элементов форм теперь вместо метода pack используется метод grid из библиотеки tkinter, потому что он обеспечивает более непротиворечивый способ размещения элементов в платформах, где размер шрифта в подписях не соответствует высоте полей ввода (включая ОС Windows 7 netbook, установленную на ноутбуке, использовавшемся для работы над этим изда-
нием). Кроме того, по всей книге были добавлены новые сведения, включая новое описание механизма переадресации потоков ввода-вывода в сокеты, в части с описанием приемов работы в Интернете; новый многопоточный диалог поиска по регулярным выражениям с поддержкой Юникода и изменения в тестах для примера PyEdit; множество других изменений, которые, вероятно, вам будет лучше раскрывать по ходу дела, чем читать о них в предисловии.
Наконец, некоторые блоки комментариев, начинающиеся с символа «#» и расположенные в начале файлов с исходными текстами, я заменил строками документирования (и, для единообразия, даже в сценариях, которые не предназначены для импортирования, хотя отдельные строки «#» остались в крупных примерах, где они отделяют текст). Я также заменил несколько устаревших операторов «while 1» на «while True»; чаще стал использовать оператор +=; внес другие изменения, исправив некоторые устаревшие шаблоны программирования. Старые привычки бывает сложно искоренять, но подобные изменения делают примеры не только более функциональными, но и более полно отражающими современные приемы программирования.
Несмотря на добавление новых тем, в общей сложности было удалено четыре главы (нетехническое введение, одна из глав с примерами по системному программированию, глава с расширенными темами, касающимися Интернета, и одна объединительная глава). Были урезаны несколько дополнительных примеров и сопутствующий им материал (включая PyForm и PyTree), а также, специально для экономии пространства, книга ограничивается представлением только версии Python 3.X и описанием лишь самых основ разработки приложений.
Что же осталось?
В результате изменений, обозначенных выше, это издание получилось более кратким и более четко отражающим основную его роль - учебное руководство по применению языка Python для решения типичных задач программирования. Однако, учитывая объем книги, можно смело утверждать, что это по-прежнему обстоятельная и всесторонняя книга, предназначенная быть первой ступенью на пути овладения мастерством разработки приложений на языке Python.
Вопреки последним настроениям (и рискуя получить клеймо еретика) я совершенно уверен, что книги, подобные этой, должны подтягивать своих читателей вверх, а не опускаться до их уровня. Снижение интеллектуальной планки вредит не только читателям, но и той области знаний, в которой они предполагают действовать. В этой книге вы не найдете множество забавных рисунков, как в некоторых, и она не будет поражать вас развлекательным повествованием вместо технической глубины. Цель моих книг состоит в том, чтобы передать сложные поня-
тия убедительным и надежным способом и снабдить вас инструментами, которые потребуются вам в разработке программного обеспечения.
Разумеется, существует множество типов обучающихся, и ни одна книга не сможет работать на любую аудиторию. Фактически именно по этой причине изначальная версия этой книги позднее была разделена на две, и описание основ языка было делегировано отдельной книге «Изучаем Python». Кроме того, и программистов можно поделить на две категории - тех, кто желает получить глубокие знания в области разработки программного обеспечения, и скриптеров, не испытывающих такой потребности. Некоторым вполне достаточно иметь элементарные знания, позволяющие дорабатывать системы или библиотеки и решать текущие проблемы. Но это пока они не начнут вторгаться в область разработки полномасштабных приложений - порог, за которым в худшем случае может наступить разочарование, а в лучшем - лучшее понимание сложной природы этой области.
Неважно, к какому лагерю вы принадлежите, важно понять основное назначение этой книги. Если вы ищете кратчайший путь к мастерству, вам едва ли понравится эта книга (как и разработка программного обеспечения в целом). Однако если вы стремитесь научиться хорошо программировать на языке Python и одновременно получить удовольствие от процесса изучения, эта книга наверняка станет для вас важной вехой на пути обретения опыта.
В конечном счете, овладеть навыками программирования далеко не так просто, как пытаются представить некоторые. Однако если вы приложите необходимые усилия, то обнаружите, что это стоит затраченного времени. Это особенно верно для тех, кто вооружает себя удобным инструментом программирования, таким как язык Python. Ни одна книга и ни одни курсы не превратят вас в «Повелителя Вселенной» Python, тем не менее цель этой книги состоит в том, чтобы помочь вам добиться этого, сократив начальный этап освоения и обеспечив надежный фундамент в наиболее типичных областях применения Python.
Влияние Python 3.X на эту книгу
Как уже упоминалось выше, это издание теперь охватывает только версию Python 3.X. Версия языка Python 3.X несовместима с версией 2.X. В своей основе язык версии 3.X очень напоминает Python 2.X, но имеет множество существенных отличий, кроющихся как в самом языке, так и в стандартной библиотеке. Читатели, не имеющие опыта работы с версией 2.X, могут пропустить описание этих отличий, но появившиеся изменения очень сильно повлияли на содержание этого издания. Для широкого круга пользователей Python 2.X в этом разделе описываются наиболее значимые изменения, относящиеся к этой категории.
Если вам интересно поближе познакомиться с отличиями от версии 2.X, я предлагаю дополнительно найти четвертое издание книги «Python Pocket Reference», упомянутое выше. Там приводятся описания основных структур языка обеих версий, 2.X и 3.X, встроенных функций и исключений, а также перечисляется большинство модулей из стандартной библиотеки и инструментов, используемых в этой книге. Хотя четвертое издание книги «Изучаем Python» не является справочником по различиям между версиями, оно охватывает обе версии,
2.X и 3.X, и, как уже отмечалось, знакомство с ней является обязательным условием для усвоения материала этой книги. Цель этого издания книги «Программирование на Python», ориентированного только на версию 3.X, заключается вовсе не в том, чтобы оставить за бортом огромное количество пользователей версии 2.X, а в том, чтобы помочь читателям перейти на новую версию и избежать увеличения размеров и без того массивной книги.
Изменения, связанные с включением поддержки версии 3.X
К счастью, многие отличия между версиями 2.X и 3.X, обусловившие необходимость внесения изменений в эту книгу, достаточно тривиальны. Например, библиотека tkinter, широко используемая в этой книге для построения графических интерфейсов, присутствует в версии 3.X под именем tkinter и имеет структуру пакета - ее прежняя инкарнация в версии 2.X, в виде модуля Tkinter, в этой книге не описывается. Это отличие приводит, в основном, к необходимости использовать отличные инструкции импортирования, но здесь приводятся только инструкции для версии Python 3. Аналогично с целью соблюдения соглашений об именовании модулей, принятых в версии 3.X, модули для версии 2.X anydbm, Queue, thread, StringIO.StringIO и urllib.open превратились в Python 3.X и в этом издании в модули dbm, queue, _thread, io. StringIO и urllib. request.urlopen соответственно. Точно так же были переименованы и другие инструменты.
С другой стороны, переход к версии 3.X предполагает более широкие идиоматические изменения, которые, конечно же, являются более радикальными. Например, усовершенствованная поддержка Юникода в Python 3.X подтолкнула к созданию для этого издания примеров полностью интернационализированных версий текстового редактора PyEdit и клиента электронной почты PyMailGUI (подробнее об этом чуть ниже). Кроме того, замена модуля os.popen2 модулем subprocess потребовала включения новых примеров; отказ от модуля os.path.walk в пользу модуля os.walk позволил сократить некоторые примеры; новое разделение на файлы и строки Юникода и двоичные файлы и строки потребовало изменения группы дополнительных примеров и описания; кроме того, появились новые модули, такие как multiprocessing, предлагающие новые возможности, которые необходимо было описать в этом издании.
Помимо изменений в библиотеке, в примерах этого издания также отражены изменения в языке Python 3. Например, здесь учтены все изменения, коснувшиеся функций из версии 2.X print, raw_input, keys, has_key, map и apply. Кроме того, новая модель импортирования относительно пакетов, появившаяся в версии 3.X, нашла отражение в некоторых примерах, таких как mailtools и анализаторы выражений, а отличия в поведении операторов деления вынудили внести небольшие изменения в примеры создания графического интерфейса, такие как PyClock, PyDraw и PyPhoto.
Замечу также, что я не стал заменять все выражения форматирования строк на основе оператора % новым методом str.format, потому что оба способа форматирования поддерживаются в Python 3.1, и похоже, оба они будут поддерживаться еще очень долго, если не всегда. Фактически если воспользоваться поиском с помощью регулярных выражений, который мы реализуем в примере текстового редактора PyEdit в главе 11, можно обнаружить, что этот оператор встречается более 3000 раз в программном коде библиотеки для Python 3.1. Я не могу с абсолютной точностью предсказать, как будет развиваться Python в будущем, поэтому обращайтесь к первой главе, где подробнее рассказывается об этом, если когда-нибудь вам потребуется внести изменения.
Кроме того, из-за того, что это издание охватывает только версию 3.X, оказалось невозможным использовать некоторые сторонние пакеты, существующие только в версии для Python 2.X, о чем уже говорилось выше. В их число входят интерфейс к MySQL, ZODB, PyCrypto и другие. Как уже упоминалось выше, для работы под управлением Python 3.1 была адаптирована библиотека PIL с целью использования в этой книге, но для этого потребовалось наложить специальные исправления, а официальная версия, поддерживающая Python 3.X, до сих пор не вышла. Многие из недостающих модулей для версии 3.X могут появиться к моменту, когда вы будете читать эти строки, либо в виде адаптированных версий для Python 2.X, либо в виде совершенно новых версий, специально для Python 3.X.
Особенности языка и библиотека: Юникод
Поскольку эта книга посвящена изучению принципов разработки приложений, а не основ языка программирования, изменения в языке не обязательно должны отслеживаться здесь. В действительности, оглядываясь на книгу «Изучаем Python», можно сказать, что изменения в языке, связанные с переходом на версию 3.X скорее касаются ее, а не данной книги. В большинстве случаев изменения в примерах к этой книге были обусловлены необходимостью сделать их более понятными или более функциональными, а не включением поддержки версии 3.X.
С другой стороны, переход на версию Python 3.X оказывает влияние на значительную часть программного кода, и иногда это влияние может оказаться весьма тонким. Тем не менее читатели с опытом использования Python 2.X обнаружат, что если отличия в версии 3.X языка чаще всего легко преодолимы, то отличия в стандартной библиотеке для версии 3.X преодолеть иногда оказывается гораздо сложнее.
Но к наиболее широким последствиям привело главное изменение в Python 3.X - улучшенная поддержка строк Юникода. Будем честными: поддержка Юникода в версии 3.X иногда может существенно осложнять жизнь тех, кто всю жизнь сталкивался только с кодировкой ASCII! Как мы увидим далее в этой книге, эта поддержка оказывает существенное влияние при работе с содержимым файлов, с именами файлов, с дескрипторами каналов, с сокетами, при выводе текста в графическом интерфейсе, при работе с такими протоколами Интернета, как FTP и email, при разработке сценариев CGI и даже при использовании некоторых инструментов хранения данных. Плохо это или хорошо, но как только мы войдем в мир разработки приложений, описываемый в этой книге, Юникод перестанет быть необязательной темой для многих, если не для большинства программистов на языке Python 3.X.
Конечно, если уж на то пошло, никому и никогда не следовало бы рассматривать использование Юникода, как дополнительную и необязательную возможность. Далее мы увидим, что некоторые приемы, которые, казалось бы, работают в Python 2.X, на самом деле нельзя признать удовлетворительными - работа с текстом как с простым набором байтов может порождать различные проблемы, такие как ошибки при сравнении строк в различных кодировках (утилита grep, реализованная в составе текстового редактора PyEdit в главе 11, является ярким примером программного кода, который должен терпеть неудачу при отказе от использования Юникода). Python 3.X обнажает подобные проблемы, делая их более заметными для программиста.
Однако перенос нетривиального программного кода на версию 3.X не является неразрешимой задачей. Кроме того, многие читатели этого издания имеют шикарную возможность начать использовать язык Python сразу же с версии 3.X и не иметь дела с существующим программным кодом для версии 2.X. Если вы принадлежите к их числу, вы увидите, что Python 3.X является надежным языком широкого применения для разработки сценариев и приложений, стремящимся устранить многие проблемы, которые когда-то скрывались в версии 2.X.
Ограничения Python 3.1: электронная почта, CGI
Здесь необходимо сделать одно важное замечание, касающееся основных примеров в книге. Чтобы их реализация представляла интерес для как можно более широкой аудитории, основные примеры в этой книге имеют отношение к электронной почте и обеспечивают поддержку интернационализации и Юникода. К этой категории относятся примеры PyMailGUI (в главе 14) и PyMailCGI (в главе 16), а также все предшествующие примеры, используемые этими приложениями, в число которых входит текстовый редактор PyEdit, поддерживающий Юникод при работе с файлами, при отображении и поиске текста.
В этом есть свои плюсы и минусы. Плюс в том, что в конечном итоге мы получим полнофункциональный и интернационализированный клиент электронной почты PyMailGUI, использующий существующий ныне пакет email. Это приложение будет поддерживать любые кодировки для содержимого и заголовков электронных писем и обеспечит возможность не только их просмотра, но и составления. Минус заключается в том, что при этом придется приложить определенные усилия, чтобы обойти сложности, связанные с особенностями реализации пакета email в Python 3.1.
К сожалению, как будет показано в главе 13, в пакете email в Python 3.1 имеется ряд проблем, связанных с обработкой типов str/bytes в Python 3.X. Например, отсутствует простой способ определить кодировку для преобразования текста письма, возвращаемого модулем poplib в виде объекта типа bytes, в тип str, который ожидает получить парсер email. Кроме того, в настоящее время пакет email не в состоянии обрабатывать некоторые виды сообщений, а поддержка некоторых типов сообщений реализована неправильно или слишком специфично.
Эта ситуация носит, скорее всего, временный характер. Исправление некоторых из проблем, с которыми нам придется столкнуться в этой книге, уже запланировано разработчиками. (Фактически из-за одного из таких исправлений, выполненных в версии 3.2, в последний момент потребовалось внести изменения в один из примеров в главе 13.) Кроме того, ведется разработка новой версии пакета email, в которой будут учтены все особенности поддержки Юникода и типа bytes в версии 3.X, но новая версия пакета будет выпущена значительно позже выхода этой книги, и она может оказаться несовместимой с API текущей версии пакета, как и сам Python 3.X. По этой причине в книге приводятся не только обходные решения, но и попутно делаются некоторые предположения. Настоятельно рекомендую регулярно посещать веб-сайт книги (описывается ниже), где будут приводиться сведения об изменениях в будущих версиях Python. Один из плюсов этой ситуации состоит в том, что детальное описание проблемы отражает существующие реалии разработки приложений - основной темы этой книги.
Проблемы, наблюдающиеся в пакете email, также в значительной степени были унаследованы реализацией модуля cgi в версии 3.1. Сценарии CGI - это одна из простейших технологий, на смену которой приходят веб-фреймворки, тем не менее они по-прежнему могут служить целям обучения основам Веб и все еще составляют основу множества крупных наборов инструментальных средств. Скорее всего, эти недостатки версии 3.1 также будут исправлены в будущем, но нам придется приложить определенные усилия, чтобы реализовать в сценариях CGI выгрузку текстовых файлов в главах 15 и 16 и вложений в сообщениях электронной почты в приложении PyMailCGI. Казалось бы, спустя два года после выхода версии Python 3.0 такое положение дел как минимум недопустимо, но такова жизнь в динамическом мире разработки программного обеспечения и в мире книг, которые стремятся вести за собой, а не плестись в хвосте.
Использование примеров из книги
Поскольку примеры составляют основную часть содержимого этой книги, я должен сказать несколько слов о них.
Где искать примеры и обновления
Как и прежде, примеры, обновления, исправления и дополнения к этой книге можно найти на веб-сайте автора, по адресу:
http://www.rmi.net/~lutz/about-pp4e.html
На этой странице веб-сайта моей книги будут даваться ссылки на дополнительную информацию, имеющую отношение к данной версии книги. Однако я не являюсь владельцем этого доменного имени, поэтому если указанная ссылка перестанет работать на протяжении срока жизни этого издания, попробуйте обратиться на другой сайт, по адресу:
http://learning-python.com/books/about-pp4e.html (альтернативная страница)
Если перестанут действовать обе ссылки, попробуйте выполнить поиск в Интернете (не сомневаюсь, что большинство читателей предпримут именно этот шаг).
На веб-сайте книги (а также на сайте издательства O’Reilly, о котором говорится в следующем разделе), где бы он ни находился, вы сможете загрузить дистрибутив с комплектом примеров - файл архива, содержащий все примеры, которые приводятся в книге, а также несколько дополнительных примеров, которые упоминаются, но отсутствуют в самой книге. Чтобы иметь возможность опробовать примеры и избавить себя от необходимости вводить их вручную, загрузите архив, распакуйте его и ознакомьтесь с содержимым файла README.txt, где приводятся инструкции по использованию. Порядок именования файлов примеров и структуру дерева каталогов пакета я опишу ниже, когда мы перейдем к опробованию первого сценария в первой главе.
Как и в случае с первыми тремя изданиями, я буду поддерживать на этом веб-сайте неофициальный «блог», где будут описываться изменения в языке Python, а также будут даваться пояснения и обновления в книге, который вы можете рассматривать, как дополнительное приложение.
Кроме того, на веб-сайте издательства O’Reilly, о котором говорится ниже, имеется система регистрации сообщений об опечатках, где вы сможете сообщить об обнаруженных ошибках. Аналогичная страница присутствует на моем сайте книги. Я стараюсь обновлять веб-сайты моих книг как можно чаще, тем не менее может так получиться, что страница на сайте издательства O’Reilly со списком опечаток будет содержать более свежую информацию. В любом случае в качестве официального источника информации об ошибках и исправлениях следует рассматривать объединение этих двух списков.
Переносимость примеров
Примеры для этой книги разрабатывались, тестировались и запускались под управлением ОС Windows 7 и Python 3.1. Непосредственно перед передачей книги в печать все основные примеры успешно прошли тестирование под управлением грядущей версии Python 3.2 (третья альфа-версия), то есть все, о чем рассказывается в этой книге, в равной степени относится и к Python 3.2. Кроме того, программный код на языке C из главы 20 и ряд примеров параллельного программирования были опробованы в Windows под управлением оболочки Cygwin, имитирующей окружение Unix.
Несмотря на то, что Python и стандартная библиотека, вообще говоря, нейтральны в отношении используемой платформы, тем не менее в некоторые примеры необходимо будет внести незначительные изменения, чтобы их можно было опробовать на других платформах, таких как Mac OS X, Linux и в других разновидностях ОС Unix. Примеры с графическим интерфейсом на основе пакета tkinter, а также некоторые примеры из раздела, посвященного системному программированию, могут быть особенно чувствительны к различиям между платформами. Часть проблем, связанных с переносимостью, будут отмечаться в ходе обсуждения примеров, но некоторые проблемы могут не упоминаться явно.
Так как у меня не было ни времени, ни возможности протестировать примеры на всех возможных платформах, какие только могут иметься в распоряжении читателей, адаптацию этих примеров для конкретной платформы предлагается рассматривать, как упражнения для самостоятельного решения. Если вы обнаружите какую-либо зависимость от типа платформы и пожелаете поделиться своими исправлениями, обращайтесь на мой сайт книги, указанный выше, - я буду рад донести до других читателей ваши исправления для любых платформ.
Сценарии запуска демонстрационных программ
В состав пакета с примерами, который был описан выше, также входят сценарии PyDemos и PyGadgets запуска демонстрационных программ. Они позволяют быстро ознакомиться с некоторыми основными примерами с графическим и веб-интерфейсом. Запускающие их сценарии, находящиеся на верхнем уровне дерева каталогов пакета с примерами, предназначены для настройки пути поиска модулей в запускаемых ими программах и могут использоваться непосредственно на совместимых платформах, включая Windows. Более подробную информацию об этих сценариях вы найдете в файлах README, а также в кратких обзорах, которые приводятся в конце главы 6 и 10.
Политика повторного использования программного кода
Мы прерываем предисловие, чтобы вставить несколько слов от имени юридического отдела. Данная книга призвана оказать вам помощь в решении ваших задач. Вообще вы можете свободно использовать примеры программного кода из этой книги в своих приложениях и в документации. Вам не нужно обращаться в издательство за разрешением, если вы не собираетесь воспроизводить существенные части программного кода. Например, если вы разрабатываете программу и используете в ней несколько отрывков программного кода из книги, вам не нужно обращаться за разрешением. Однако в случае продажи или распространения компакт-дисков с примерами из этой книги вам необходимо получить разрешение от издательства O’Reilly. Для цитирования данной книги или примеров из нее, при ответе на вопросы не требуется получение разрешения. При включении существенных объемов программного кода примеров из этой книги в вашу документацию вам необходимо будет получить разрешение издательства.
Мы приветствуем, но не требуем добавлять ссылку на первоисточник при цитировании. Под ссылкой на первоисточник мы подразумеваем указание названия книги, авторов, издательства и ISBN. Например: «Programming Python, Fourth Edition, by Mark Lutz (O’Reilly). Copyright 2011 Mark Lutz, 978-0-596-15810-1».
Как связаться с издательством O'Reilly
В предыдущем разделе я описал свои собственные сайты, где можно найти примеры и обновления. В дополнение к тем сайтам вы можете обратиться на сайт издательства с вопросами и предложениями, касающимися этой книги:
O’Reilly Media
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (в Соединенных Штатах Америки или в Канаде)
707-829-0515 (международный)
707-829-0104 (факс)
Как уже говорилось выше, на сайте издательства O’Reilly поддерживается веб-страница для этой книги, где можно найти список опечаток, файлы с примерами и другую дополнительную информацию:
http://www.oreilly.com/catalog/9780596158101
Свои пожелания и вопросы технического характера отправляйте по адресу:
bookquestions@oreilly.com
Дополнительную информацию о книгах, обсуждения, программное обеспечение, Центр ресурсов издательства O’Reilly вы найдете на сайте:
http://www.oreilly.com
Типографские соглашения
В этой книге приняты следующие соглашения:
Курсив
Курсив применяется для выделения имен файлов и каталогов, новых терминов и некоторых комментариев в примерах программного кода.
Моноширинный шрифт
Применяется для представления листингов программ, а также для выделения в обычном тексте программных элементов, таких как имена модулей, методов, параметров, классов, функций, инструкций, программ, объектов и тегов HTML.
Моноширинный жирный
Используется для выделения команд или текста, который должен быть введен пользователем.
Моноширинный курсив
Обозначает элементы в программном коде, которые должны быть замещены, исходя из конкретной ситуации.
Так выделяются примечания, имеющие отношение к текущему обсуждению.
Так выделяются предупреждения или предостережения, имеющие отношение к текущему обсуждению.
Благодарности
Я благодарен всем, кто перечислен в предисловии к четвертому изданию книги «Изучаем Python», вышедшему меньше года тому назад. Так как знакомство с книгой «Изучаем Python» является обязательным условием для чтения этой книги, а также потому что люди, помогавшие мне в создании обеих книг, - одни и те же, я не стал повторять весь список здесь. Но, как бы то ни было, я хотел бы выразить благодарность:
• Издательству O’Reilly за продвижение Python и публикацию серьезных и содержательных книг, имеющих отношение к программному обеспечению с открытыми исходными текстами
• Сообществу Python, составляющему большую часть моего мира начиная с 1992 года
• Тысячам студентов, прошедших через 250 курсов обучения языку Python, которые я провел начиная с 1997 года
• Сотням тысяч читателей, прочитавшим 12 изданий всех трех моих книг о Python, которые вышли с 1995 года
• Монти Пайтону (Monty Python), тезке Python, за множество интересных ситуаций, в которых есть чему поучиться (подробнее об этом - в следующей главе)
Книгу пишет обычно один человек, но многие идеи рождаются в сообществе. Я благодарен за отклики, которые мне повезло получить в течение последних 18 лет от моих студентов и читателей. Студенты - лучшие учителя учителей.
С личной стороны я хотел бы сказать спасибо моим братьям и сестре за старые добрые времена, а также моим детям, Майклу (Michael), Саманте (Samantha) и Роксане (Roxanne), за возможность гордиться ими.
А особенная благодарность моей супруге Вере (Vera), которой так или иначе удалось внести немало хорошего в этот в каком-то смысле неизменяемый объект.
Марк Лутц (Mark Lutz), июль 2010
Так что же такое Python?
Как уже говорилось выше, в этой книге не будет уделяться большое внимание основам Python, и мы отложим абстрактные рассуждения о роли Python до заключительной главы, то есть до того момента, когда вы познакомитесь с этим языком программирования на практике. Тем не менее если вы хотите получить исчерпывающее определение темы этой книги, извольте:
Python - это язык программирования общего назначения, распространяемый с открытыми исходными текстами (open source). Он оптимизирован для создания качественного программного обеспечения, высокой производительности труда разработчиков, переносимости программ и интеграции компонентов. Язык Python используется сотнями тысяч разработчиков по всему миру в таких областях, как создание веб-сценариев, системное программирование, создание пользовательских интерфейсов, настройка программных продуктов под пользователя, численное программирование и в других. Как считают многие, один из самых используемых языков программирования в мире.
Как популярный язык, обеспечивающий сокращение времени, затрачиваемого на разработку программ, Python используется для создания широкого круга программ в самых разных областях. В число пользователей Python в настоящее время входят Google, YouTube, Industrial Light & Magic, ESRI, системы BitTorrent обмена файлами, Jet Propulsion Lab в NASA, игра Eve Online и National Weather Service (национальная метеорологическая служба, США). Язык Python используется в самых разных областях, от администрирования систем, разработки веб-сайтов, создания сценариев для мобильных устройств и обучения, до тестирования аппаратуры, анализа капиталовложений, компьютерных игр и управления космическими кораблями.
Среди прочих достоинств, Python отличается удивительной простотой, удобочитаемостью и простым синтаксисом; он легко интегрируется с внешними компонентами, написанными на других языках программирования; имеет мультипарадигменную архитектуру и поддерживает объектно-ориентированное, функциональное и модульное программирование; обладает обширной коллекцией уже запрограммированных интерфейсов и утилит. Набор встроенных инструментальных средств делает его необычайно гибким и динамичным языком программирования, идеально подходящим не только для быстрого решения тактических задач, но и для разработки перспективных стратегических решений. Несмотря на свое общее назначение, Python часто называют языком сценариев, так как он позволяет легко и просто использовать другие программные компоненты и управлять ими.
Самым большим достоинством Python является, пожалуй, то, что с его помощью разработка программного обеспечения становится более быстрой и приятной. Есть такая категория людей, для которых программирование является самоцелью. Они наслаждаются самим процессом. Пишут программы исключительно для собственного удовольствия, а коммерческие или карьерные выгоды рассматривают лишь, как вторичное следствие. Именно такие люди в значительной степени причастны к появлению Интернета, движения за распространение программного обеспечения с открытыми исходными текстами (open source) и Python. Эти же люди исторически являются основными читателями этой книги. От них часто можно услышать, что с таким инструментом, как Python, программирование превращается в настоящее развлечение.
Чтобы понять, как это происходит, читайте дальше. Как побочный эффект, значительная часть этой книги представляет собой демонстрацию воплощения идеалов Python в действующий программный код. Как мы увидим далее, особенно когда будем знакомиться с инструментальными средствами, используемыми для создания графического интерфейса пользователя, веб-сайтов, в системном программировании и так далее, Python способствует продвижению новых технологий.
Об авторе
Марк Лутц (Mark Lutz) является ведущим специалистом в области обучения языку программирования Python, автором самых ранних и наиболее популярных публикаций и известен в сообществе пользователей Python своими новаторскими идеями.
Марк является автором книг «Изучаем Python», «Программирование на Python» и «Python Pocket Reference», выпущенных издательством O’Reilly, каждая из которых претерпела уже четыре издания. Он использует Python и занимается его популяризацией начиная с 1992 года; книги о Python начал писать в 1995 году; преподаванием этого языка программирования стал заниматься с 1997 года. На начало 2010 года Марк провел 250 курсов, обучил более 3500 студентов, написал книги по языку Python, суммарный тираж которых составил примерно четверть миллиона копий и которые были переведены более чем на десять языков.
Обладает степенями бакалавра и магистра в области информатики, закончи* университет штата Висконсин (США). На протяжении последних 25 лет занимался разработкой компиляторов, инструментальных средств программиста, приложений и разнообразных систем в архитектуре клиент/сервер. Связаться с Марком можно через веб-сайт книги http://rmi.net/~lutz и веб-сайт курсов, которые он ведет: http://learning-python.com.
I
Начало
Эта часть книги запускает повествование, предлагая краткий экскурс, в котором рассматриваются фундаментальные понятия языка Python и представляются некоторые из наиболее типичных приемов его использования.
Глава 1
Эта глава начинает рассказ с простого примера - записи информации о людях, - что позволит коротко представить некоторые из основных областей применения языка Python, которые мы будем изучать в этой книге. Мы заставим этот пример существовать в самых разных ситуациях. По пути мы встретимся с базами данных, графическими интерфейсами, веб-сайтами и так далее. Эта своего рода демонстрационная глава задумывалась с целью возбудить в вас интерес. Здесь мы не будем исследовать все аспекты, но у нас будет возможность увидеть Python в действии, прежде чем мы погрузимся в детали. Данная глава служит также обзором некоторых базовых идей языка, с которыми вы должны быть знакомы, прежде чем приступать к чтению этой книги, - такими как представление данных и объектно-ориентированное программирование (ООП).
Назначение этой части книги не в том, чтобы дать вам всесторонний обзор языка Python, а в том, чтобы познакомить вас с примером его применения и предоставить краткий обзор определенного круга задач, решаемых с помощью языка Python.
1
Предварительный обзор
«Программирование на Python»: краткий очерк
Если вы берете в руки книгу такого размера, как эта, то вам, как и большинству людей, перед тем как засучить рукава, наверняка захочется немного узнать о том, что вы собираетесь изучать. Именно об этом рассказывает данная глава - в ней приводятся несколько примеров, которые позволят вам оценить возможности языка Python, прежде чем вы перейдете к изучению подробностей. Здесь вы найдете лишь краткие пояснения, поэтому если у вас появится желание получить подробное описание инструментов и приемов, использованных в этой главе, вам придется прочитать последующие части книги. Цель этой главы состоит в том, чтобы возбудить у вас аппетит кратким обзором основ языка Python и ознакомлением с некоторыми темами, рассматриваемыми далее.
Для этого я возьму довольно простое приложение, конструирующее базу данных, и проведу вас через различные этапы его создания: моделирование в интерактивном режиме, использование инструментов командной строки, создание интерфейса командной строки, создание графического интерфейса и создание простого веб-интерфейса. Попутно мы познакомимся с такими понятиями, как представление данных, сохранение объектов и объектно-ориентированное программирование (ООП); исследуем несколько альтернативных решений, к которым вернемся позднее; и рассмотрим некоторые основные идеи языка Python, которые вы должны знать, прежде чем продолжать чтение этой книги. В конечном итоге мы получим базу данных, хранящую экземпляры класса, которые можно будет просматривать и изменять с использованием различных интерфейсов.
Конечно, далее я затрону и дополнительные темы, но приемы, которые будут представлены здесь, применимы к некоторым прикладным областям, которые мы будем исследовать далее. Замечу также, что если что-то в программах из этой главы для вас останется непонятным, не волнуйтесь, так и должно быть - пока, по крайней мере. Здесь просто демонстрируются возможности Python. С недостающими подробностями вы познакомитесь достаточно скоро. А теперь начнем с небольшого развлечения.
Читатели четвертого издания книги «Изучаем Python» могут заметить в примере из этой главы знакомые черты - здесь участвуют те же персонажи, что и в главе про ООП в книге «Изучаем Python», а последние версии примера, основанные на использовании классов, по сути являются вариациями на ту же тему. Не боясь обвинений в избыточности, я здесь возвращаюсь к этому примеру по трем причинам: он вполне может использоваться для обзора основных возможностей языка; некоторые читатели этой книги не читали «Изучаем Python»; здесь этот пример получает дальнейшее развитие за счет добавления графического и веб-интерфейсов. Таким образом, эта глава начинается с того места, где закончилась книга «Изучаем Python», и помещает этот пример использования основных возможностей языка в контекст действующего приложения, что в общих чертах соответствует цели этой книги.
Постановка задачи
Представьте, что по некоторым причинам вам необходимо хранить информацию о людях. Это может быть адресная книга на вашем компьютере или, возможно, информация о служащих вашей фирмы. По каким-либо причинам вам требуется написать программу, которая сохраняла бы информацию об этих людях. Другими словами, вам требуется организовать сохранение записей в базе данных, чтобы обеспечить возможность долговременного хранения в компьютере списка людей с информацией о них.
Естественно, существует множество уже готовых программ для работы с базами данных. Однако, написав свою программу, вы получите полный контроль над тем, как она действует. Вы сможете добавлять в нее обработку специальных случаев, которые, возможно, не предусматриваются стандартным программным обеспечением. Вам не придется устанавливать базу данных и учиться пользоваться ею. И вам не придется ждать, пока поставщик программного обеспечения исправит ошибки или добавит новые особенности. Итак, вы решили написать на языке Python программу, управляющую информацией о людях.
Шаг 1: представление записей
Коль скоро мы собрались сохранять записи в базе данных, на самом первом этапе нам необходимо решить, как будут выглядеть эти записи. В языке Python имеется масса способов представления информации о людях. Зачастую для этих целей вполне достаточно бывает использовать объекты встроенных типов, такие как списки и словари, особенно если изначально не требуется предусматривать обработку сохраняемых данных.
Списки
Списки, например, позволяют сохранять информацию о людях упорядоченным способом. Запустите интерпретатор Python в интерактивном режиме и введите следующие две инструкции:
>>> bob = [‘Bob Smith', 42, 30000, 'software']
>>> sue = [‘Sue Jones', 45, 40000, ‘hardware']
Мы только что создали две простые записи, представляющие информацию о Бобе (Bob) и Сью (Sue) (мои извинения, если вас действительно зовут Боб или Сью3). Каждая запись является списком с четырьмя элементами: имя, возраст, оклад и должность. Чтобы получить доступ к этим элементам, достаточно просто использовать операцию индексирования. Результат в примере ниже заключен в круглые скобки потому, что он является кортежем из двух результатов:
>>> bob[0], sue[2] # получить имя и оклад
(‘Bob Smith’, 40000)
В таком представлении записи легко обрабатывать - достаточно просто использовать операции над списками. Например, можно получить фамилию человека, разбив поле с именем по пробельному символу и отобрав последнюю часть, точно так же можно повысить оклад, изменив соответствующий список:
>>> bob[0].split()[-1] # получить фамилию Боба
‘Smith’
>>> sue[2] *= 1.25 # повысить оклад Сью на 25%
>>> sue
[‘Sue Jones’, 45, 50000.0, ‘hardware’]
Выражение, извлекающее фамилию в этом примере, обрабатывается интерпретатором слева направо: сначала извлекается строка с именем и фамилией Боба, затем строка разбивается по пробелам и преобразуется в список подстрок, а операция индексирования возвращает фамилию (разбейте это выражение на несколько операций, чтобы увидеть, как это происходит).
Первые замечания
Поскольку это первый пример программного кода в книге, необходимо сделать несколько практических замечаний:
• Этот программный код можно ввести в среде IDLE с графическим интерфейсом; после ввода команды python в командной строке (или той же команды с указанием полного пути к ней, если она не находится в системном списке путей поиска выполняемых файлов) и так далее.
• Символы >>> characters - это приглашение к вводу интерпретатора Python (эти символы не нужно вводить).
• Информационные строки, которые интерпретатор Python выводит при запуске, я опустил ради экономии места.
• Все примеры из этой книги я запускал под управлением Python 3.1; результаты работы примеров во всех версиях линейки 3.X должны быть одинаковыми (разумеется, исключая непредвиденные случаи внесения существенных изменений в Python).
• Большая часть примеров в этой книге, за исключением некоторых из них, демонстрирующих приемы системного программирования и интеграции с программным кодом на языке C, выполнялись в ОС Windows 7. Однако, благодаря переносимости Python, не имеет значения, в какой операционной системе будут опробоваться примеры, если иное не указано явно.
Если прежде вам не доводилось выполнять программный код на языке Python подобным способом, тогда обращайтесь за справочной информацией к вводным материалам, таким как книга «Изучаем Python». Далее в этой главе я сделаю несколько замечаний, касающихся запуска программного кода, хранящегося в файлах сценариев.
База данных в виде списка
К настоящему моменту мы всего создали всего лишь две переменных, но не базу данных. Чтобы объединить информацию о Бобе и Сью, мы могли бы просто включить ее в другой список:
>>> people = [bob, sue] # ссылки в списке списков
>>> for person in people: print(person)
[‘Bob Smith’, 42, 30000, ‘software’]
[‘Sue Jones’, 45, 50000.0, ‘hardware’]
Теперь нашу базу данных представляет список people. Мы можем извлекать из него отдельные записи в соответствии с их позициями в списке и обрабатывать их в цикле:
>>> people[1][0]
‘Sue Jones’
>>> for person in people:
print(person[0].split()[-1]) # вывести фамилию
person[2] *= 1.20 # увеличить оклад на 20%
Smith
Jones
>>> for person in people: print(person[2]) # проверить новый размер оклада
36000.0
60000.0
Теперь, когда у нас имеется список, мы можем организовать выборку значений полей из записей с помощью более мощных инструментов выполнения итераций, присутствующих в языке Python, таких как генераторы списков, функция map и выражения-генераторы:
>>> pays = [person[2] for person in people] # выбрать все оклады >>> pays
[36000.0, 60000.0]
>>> pays = map((lambda x: x[2]), people) # то же самое (в версии 3.X
>>> list(pays) # функция map возвращает генератор)
[36000.0, 60000.0]
>>> sum(person[2] for person in people) # выражение-генератор,
96000.0 # sum - встроенная функция
Для добавления новых записей в базу данных вполне достаточно использовать обычные операции над списками, такие как append и extend:
>>> people.append(['Tom', 50, 0, None])
>>> len(people)
3
>>> people[-1][0]
‘Tom’
Списки неплохо подходят для реализации нашей базы данных, и их возможностей вполне достаточно для некоторых программ, но они страдают рядом существенных недостатков. Во-первых, информация о Бобе и Сью в настоящий момент хранится в виде объектов в оперативной памяти, и она будет утеряна сразу после завершения работы интерпретатора Python. Во-вторых, всякий раз, когда потребуется извлечь фамилию человека или повысить ему оклад, нам придется повторно вводить программный код, который мы только что видели. Это может вызвать определенные проблемы, если когда-нибудь поменяется алгоритм выполнения этих операций, - нам может потребоваться изменить наш программный код во многих местах. Мы вернемся к этим проблемам через несколько минут.
Обращение к полям по именам
Самый, пожалуй, существенный недостаток при использовании списков заключается в необходимости запоминать позиции полей: как иначе можно утверждать, что программный код, обращающийся к элементу записи с таинственным индексом 2, извлекает размер оклада? С точки зрения очевидности программного кода было бы лучше, если бы можно было присвоить каждому полю осмысленное имя.
Мы могли бы связать имена с позициями полей в записи, используя встроенную функцию range, которая генерирует набор последовательных целых чисел при использовании в контексте итераций (таких как операция присваивания последовательности ниже):
>>> NAME, AGE, PAY = range(3) # 0, 1 и 2
>>> bob = ['Bob Smith’, 42, 10000]
>>> bob[NAME]
‘Bob Smith’
>>> PAY, bob[PAY]
(2, 10000)
Это решает проблему читаемости программного кода: три имени переменных, состоящих из заглавных символов, по сути, превратились в имена полей. Однако такое решение делает программный код зависящим от инструкции присваивания позиций именам полей, - мы должны помнить о необходимости обновлять ее при любом изменении структуры записи. Поскольку имена полей и записи никак не связаны между собой, они могут перестать соответствовать друг другу, и тогда возникнет необходимость вмешательства в программный код.
Кроме того, так как имена полей являются независимыми переменными, между записью в виде списка и именами полей отсутствует обратная связь. Имея одну только запись в виде списка, например, нельзя реализовать форматированный вывод значений полей с их именами. В случае с предыдущей записью без дополнительных ухищрений невозможно получить имя AGE из значения 42: вызов bob.index(42) вернет 1, значение переменной AGE, но не само имя AGE.
Можно было бы попробовать представлять записи в виде списков кортежей, где кортежи хранят не только значения полей, но их имена. Но еще лучше было бы использовать списки списков, что позволило бы изменять поля (кортежи относятся к категории неизменяемых объектов). Ниже демонстрируется воплощение этой идеи на примере простых записей:
>>> bob = [['name', ‘Bob Smith'], ['age', 42], ['pay', 10000]]
>>> sue = [['name', ‘Sue Jones'], ['age', 45], ['pay', 20000]]
>>> people = [bob, sue]
Однако на самом деле этот прием не решает проблему, потому что для извлечения полей все равно необходимо использовать числовые индексы:
>>> for person in people:
print(person[0][1], person[2][1]) # имя, оклад
Bob Smith 10000 Sue Jones 20000
>>> [person[0][1] for person in people] # выборка имен [‘Bob Smith’, ‘Sue Jones’]
>>> for person in people:
print(person[0][1].split()[-1]) # получить фамилию person[2][1] *= 1.10 # повысить оклад на 10%
Smith
Jones
>>> for person in people: print(person[2])
[‘pay’, 11000.0]
[‘pay’, 22000.0]
Все, чего мы добились, - добавили еще один уровень индексирования. Для достижения желаемого мы могли бы просматривать имена полей в цикле, отыскивая необходимые (в следующем цикле используется операция присваивания кортежа для распаковывания пар имя/значение):
>>> for person in people:
for (name, value) in person:
if name == ‘name': print(value) # поиск требуемого поля
Bob Smith Sue Jones
Еще лучше было бы реализовать функцию, выполняющую всю работу за нас:
>>> def field(record, label):
for (fname, fvalue) in record:
if fname == label: # поиск поля по имени
return fvalue
>>> field(bob, ‘name')
‘Bob Smith’
>>> field(sue, ‘pay')
22000.0
>>> for rec in people: # вывести возраст всех людей
print(field(rec, ‘age')) # в базе данных
42
45
Если двигаться дальше по этому пути, в конечном итоге можно получить набор функций, осуществляющих интерфейс к записям, отображающих имена полей в их значения. Однако если прежде вам приходилось программировать на языке Python, вы наверняка знаете, что существует более простой способ реализации такого рода ассоциаций, и вы уже наверняка догадались, в какую сторону мы направимся в следующем разделе.
Словари
Реализация записей на основе списков, как было показано в предыдущем разделе, вполне работоспособна, хотя и за счет некоторой потери производительности из-за необходимости выполнять поиск полей по именам (если вас волнуют потери, измеряемые миллисекундами). Однако если вы уже имеете некоторое знакомство с языком Python, вы должны знать, что существуют более эффективные и более удобные способы связывания имен полей с их значениями. Встроенные объекты словарей выглядят естественно:
>>> bob = {‘name': ‘Bob Smith', ‘age': 42, ‘pay': 30000, ‘job': ‘dev'}
>>> sue = {‘name': ‘Sue Jones', ‘age': 45, ‘pay': 40000, ‘job': ‘hdw'}
Теперь bob и sue - это объекты, автоматически отображающие имена полей в их значения, и их использование делает программный код более простым и понятным. Нам не требуется запоминать, что означают числовые индексы, и мы даем интерпретатору возможность использовать его высокоэффективный алгоритм индексации словарей, чтобы отыскивать значения полей, ассоциированные с их именами:
>>> bob[‘name'], sue[‘pay'] # в отличие от bob[0], sue[2]
(‘Bob Smith’, 40000)
>>> bob[‘name'].split()[-1]
‘Smith’
>>> sue[‘pay'] *= 1.10
>>> sue[‘pay']
44000.0
Поскольку теперь при обращении к полям используются символические имена, программный код выглядит более осмысленным для всех, кто будет читать его (включая и вас).
Другие способы создания словарей
Словари являются настолько удобными объектами при программировании на языке Python, что было предусмотрено еще несколько способов их создания, отличающихся от традиционного синтаксиса литералов, продемонстрированного выше, - например, вызовом конструктора с именованными аргументами, при этом все ключи будут строками:
>>> bob = dict(name='Bob Smith', age=42, pay=30000, job='dev')
>>> sue = dict(name='Sue Jones', age=45, pay=40000, job='hdw')
>>> bob
{‘pay’: 30000, ‘job’: ‘dev’, ‘age’: 42, ‘name’: ‘Bob Smith’}
>>> sue
{‘pay’: 40000, ‘job’: ‘hdw’, ‘age’: 45, ‘name’: ‘Sue Jones’}
заполнением словаря поле за полем (напомню, что для ключей словаря не предусматривается какой-то определенный порядок следования):
>>> sue = {}
>>> sue[‘name'] = ‘Sue Jones'
>>> sue[‘age'] = 45 >>> sue[‘pay'] = 40000 >>> sue[‘job'] = ‘hdw'
>>> sue
{‘job’: ‘hdw’, ‘pay’: 40000, ‘age’: 45, ‘name’: ‘Sue Jones’}
объединением двух списков, содержащих имена и значения:
>>> names = [‘name', ‘age', ‘pay', ‘job']
>>> values = [‘Sue Jones', 45, 40000, ‘hdw']
>>> list(zip(names, values))
[(‘name’, ‘Sue Jones’), (‘age’, 45), (‘pay’, 40000), (‘job’, ‘hdw’)]
>>> sue = dict(zip(names, values))
>>> sue
{‘job’: ‘hdw’, ‘pay’: 40000, ‘age’: 45, ‘name’: ‘Sue Jones’}
Словари можно даже создавать из последовательностей ключей и необязательного начального значения для всех ключей (этот способ удобно использовать для инициализации пустых словарей):
>>> fields = (‘name', ‘age', ‘job', ‘pay')
>>> record = dict.fromkeys(fields, ‘?')
>>> record
{‘job’: ‘?’, ‘pay’: ‘?’, ‘age’: ‘?’, ‘name’: ‘?’}
Списки словарей
Независимо от способа создания словарей, нам все еще необходимо собрать словари-записи в базу данных. Здесь также можно использовать список, при условии, что нам не требуется обеспечить доступ по ключу на верхнем уровне:
>>> bob
{‘pay’: 30000, ‘job’: ‘dev’, ‘age’: 42, ‘name’: ‘Bob Smith’}
>>> sue
{‘job’: ‘hdw’, ‘pay’: 40000, ‘age’: 45, ‘name’: ‘Sue Jones’}
>>> people = [bob, sue] # ссылки в списке
>>> for person in people:
print(person[‘name'], person[‘pay'], sep=', ‘) # все имена, оклады
Bob Smith, 30000 Sue Jones, 40000
>>> for person in people:
if person[‘name'] == ‘Sue Jones': # оклад Сью
print(person[‘pay'])
40000
Здесь точно так же используются инструменты итераций, но вместо таинственных числовых индексов используются ключи (в терминах баз данных генератор списков и функция map в следующем примере возвращают проекцию базы данных по полю «name»):
>>> names = [person[‘name'] for person in people] # выбирает имена >>> names
[‘Bob Smith’, ‘Sue Jones’]
>>> list(map((lambda x: x[‘name']), people)) # то же самое
[‘Bob Smith’, ‘Sue Jones’]
>>> sum(person[‘pay'] for person in people) # сумма всех окладов
70000
Интересно, что такие инструменты, как генераторы списков и выражения-генераторы, способны по своему удобству приблизиться к запросам в языке SQL, с тем отличием, что они манипулируют объектами в памяти:
>>> [rec[‘name'] for rec in people if rec[‘age'] >= 45] # SQL-подобный
[‘Sue Jones’] # запрос
>>> [(rec[‘age'] ** 2 if rec[‘age'] >= 45 else rec[‘age']) for rec in people]
[42, 2025] >>> G = (rec[‘name'] for rec in people if rec[‘age'] >= 45)
>>> next(G)
‘Sue Jones’
>>> G = ((rec[‘age'] ** 2 if rec[‘age'] >= 45 else rec[‘age']) for rec in people)
>>> G.__next__()
42
А так как словари являются обычными объектами, к этим записям можно также обращаться с использованием привычного синтаксиса:
>>> for person in people:
print(person[‘name'].split()[-1]) # фамилия
person[‘pay'] *= 1.10 # повышение на 10%
Smith
Jones
>>> for person in people: print(person[‘pay'])
33000.0
44000.0
Вложенные структуры
В предыдущих примерах мы могли бы при желании избежать необходимости писать дополнительный программный код, извлекающий фамилии, еще больше структурировав наши записи. Поскольку в языке все объекты составных типов данных могут вкладываться друг в друга сколь угодно глубоко, мы легко можем конструировать чрезвычайно сложные структуры данных, используя простой синтаксис объектов, а Python сам позаботится о создании компонентов, связывании структур в памяти и освобождении памяти позднее. Это одно из значительных преимуществ таких языков сценариев, как Python.
В следующем примере демонстрируется более структурированная запись, содержащая вложенный словарь, список и кортеж внутри другого словаря:
>>> bob2 = {‘name': {‘first': ‘Bob', ‘last': ‘Smith'},
‘age': 42,
‘job': [‘software', ‘writing'],
‘pay': (40000, 50000)}
Эта запись содержит вложенные структуры, поэтому для доступа к более низкому уровню мы просто будем использовать двойные индексы:
>>> bob2[‘name'] # полное имя Боба
{‘last’: ‘Smith’, ‘first’: ‘Bob’}
>>> bob2[‘name'][‘last'] # фамилия Боба
‘Smith’
>>> bob2[‘pay'][1] # верхний предел оклада Боба
50000
Поле name здесь - это еще один словарь, поэтому вместо того чтобы разбивать строку для извлечения фамилии, мы просто используем операцию индексирования. Кроме того, сотрудники могут занимать несколько должностей, а также иметь верхний и нижний предел оклада. Фактически в подобных ситуациях Python превращается в своеобразный язык запросов - мы можем извлекать и изменять вложенные значения с применением обычных операций над объектами:
>>> for job in bob2[‘job']: print(job) # все должности, занимаемые Бобом
software
writing
>> bob2[‘job'][-1] # последняя должность Боба
‘writing’
>>> bob2[‘job'].append(‘janitor') # Боб получает новую должность >>> bob2
{‘job’: [‘software’, ‘writing’, ‘janitor’], ‘pay’: (40000, 50000), ‘age’: 42, ‘name’: {‘last’: ‘Smith’, ‘first’: ‘Bob’}}
В расширении вложенного списка с помощью метода append нет ничего необычного, потому что в действительности он является независимым объектом. Такие вложенные конструкции могут пригодиться в более сложных приложениях. Однако, чтобы не усложнять примеры, мы сохраним прежнюю, плоскую структуру записей.
Словари словарей
И еще один поворот в реализации нашей базы данных с информацией о людях: мы можем расширить область применения словарей, задействовав еще один словарь для представления самой базы данных. То есть мы можем создать словарь словарей - внешний словарь будет играть роль базы данных, а вложенные словари - роль записей. В отличие от простого списка записей, база данных, представленная в виде словаря, позволит нам сохранять и извлекать записи с помощью символических ключей:
>>> bob = dict(name='Bob Smith', age=42, pay=30000, job='dev')
>>> sue = dict(name='Sue Jones', age=45, pay=40000, job='hdw')
>>> bob
{‘pay’: 30000, ‘job’: ‘dev’, ‘age’: 42, ‘name’: ‘Bob Smith’}
>>> db = {}
>>> db[‘bob'] = bob # ссылки на словари в словаре
>>> db[‘sue'] = sue
>>>
>>> db[‘bob'][‘name'] # извлечь имя Боба
‘Bob Smith’
>>> db[‘sue'][‘pay'] = 50000 # изменить оклад Сью
>>> db[‘sue'][‘pay'] # извлечь оклад Сью
50000
Обратите внимание, что такая организация позволяет нам обращаться к записям непосредственно, без необходимости выполнять поиск в цикле - мы получаем непосредственный доступ к записи с информацией о Бобе за счет использования ключа bob. Это действительно словарь словарей, хотя это и не заметно, если не вывести всю базу данных сразу (для подобных целей удобно использовать модуль pprint форматированного вывода):
>>> db
{‘bob’: {‘pay’: 30000, ‘job’: ‘dev’, ‘age’: 42, ‘name’: ‘Bob Smith’}, ‘sue’: {‘pay’: 50000, ‘job’: ‘hdw’, ‘age’: 45, ‘name’: ‘Sue Jones’}}
>>> import pprint >>> pprint.pprint(db)
{‘bob’: {‘age’: 42, ‘job’: ‘dev’, ‘name’: ‘Bob Smith’, ‘pay’: 30000},
‘sue’: {‘age’: 45, ‘job’: ‘hdw’, ‘name’: ‘Sue Jones’, ‘pay’: 50000}}
Если же возникнет необходимость последовательно обойти все записи в базе данных, можно воспользоваться итераторами словарей. В последних версиях Python реализован итератор словаря, который на каждой итерации в цикле for воспроизводит по одному ключу (для совместимости с более ранними версиями в циклах for можно также вместо простого имени db использовать явный вызов метода db. keys, но, так как в Python 3 метод keys возвращает генератор, конечный результат будет тот же самый):
>>> for key in db:
print(key, ‘=>', db[key][‘name'])
bob => Bob Smith sue => Sue Jones
>>> for key in db:
print(key, ‘=>', db[key][‘pay'])
bob => 30000 sue => 50000
В процессе обхода доступ к отдельным записям можно получать с использованием операции индексирования по ключу:
>>> for key in db:
print(db[key][‘name'].split()[-1]) db[key][‘pay'] *= 1.10
Smith
Jones
или напрямую, организовав обход значений словаря:
>>> for record in db.values(): print(record[‘pay'])
33000.0
55000.0
>>> x = [db[key][‘name'] for key in db]
>>> x
[‘Bob Smith’, ‘Sue Jones’]
>>> x = [rec[‘name'] for rec in db.values()]
>>> x
[‘Bob Smith’, ‘Sue Jones’]
А чтобы добавить новую запись, достаточно просто выполнить операцию присваивания по новому ключу. В конце концов - это всего лишь словарь:
>>> db[‘tom'] = dict(name='Tom', age=50, job=None, pay=0)
>>>
>>> db[‘tom']
{‘pay’: 0, ‘job’: None, ‘age’: 50, ‘name’: ‘Tom’}
>>> db[‘tom'][‘name']
‘Tom’
>>> list(db.keys())
[‘bob’, ‘sue’, ‘tom’]
>>> len(db)
3
>>> [rec[‘age'] for rec in db.values()]
[42, 45, 50]
>>> [rec[‘name'] for rec in db.values() if rec[‘age'] >= 45] # SQL-подобный [‘Sue Jones’, ‘Tom’] # запрос
Наша база данных по-прежнему является объектом, хранящимся в оперативной памяти. Но, как оказывается, такой формат словаря словарей в точности соответствует формату, который используется системой сохранения объектов в файлах, - модулем shelve (с точки зрения грамматики английского языка этот модуль должен был бы называться shelf, но в Python термин shelve, обозначающий сохранение объектов, одновременно служит и названием соответствующего ему модуля). О том, как это делается, вы узнаете в следующем разделе.
Шаг 2: сохранение записей на длительное время
К настоящему моменту мы остановились на представлении нашей базы данных в виде словаря и попутно рассмотрели некоторые способы реализации структур данных в языке Python. Однако, как уже упоминалось выше, объекты, с которыми мы имели дело до сих пор, - временные объекты; они располагаются в оперативной памяти и исчезают бесследно после завершения работы интерпретатора Python или программы, создавшей их. Чтобы обеспечить долговременное хранение базы данных, ее необходимо сохранить в каком-нибудь файле.
Текстовые файлы
Один из способов обеспечить сохранность данных между запусками программы заключается в сохранении всех данных в простом файле, в виде отформатированного текста. Выработав определенную договоренность о формате представления данных, которая будет использоваться инструментами чтения и записи, мы сможем реализовать любую схему хранения.
Тестовый сценарий создания данных
Чтобы не продолжать дальнейшую работу в интерактивном режиме, напишем сценарий, инициализирующий базу данных, которую требуется сохранить (если вы уже имеете опыт работы с языком Python, то должны знать, что как только вы начинаете писать программный код, занимающий больше одной строки, работа в интерактивном режиме становится утомительной). Сценарий в примере 1.1 создает несколько записей и словарь базы данных, с которыми мы работали до сих пор, но так как он одновременно является модулем, мы сможем импортировать его и избавиться от необходимости всякий раз вводить программный код вручную. В некотором смысле этот модуль и является базой данных, но его реализация не поддерживает возможность изменения данных автоматически или конечным пользователем.
Пример 1.1. PP4E\Preview\initdata.py
# инициализировать данные для последующего сохранения в файлах
# записи
bob = {‘name’: ‘Bob Smith’, ‘age’: 42, ‘pay’: 30000, ‘job’: ‘dev’}
sue = {‘name’: ‘Sue Jones’, ‘age’: 45, ‘pay’: 40000, ‘job’: ‘hdw’}
tom = {‘name’: ‘Tom’, ‘age’: 50, ‘pay’: 0, ‘job’: None}
# база данных db = {}
db[‘bob’] = bob db[‘sue’] = sue db[‘tom’] = tom
if __name__ == ‘__main__’: # если запускается, как сценарий
for key in db:
print(key, ‘=>\n ‘, db[key])
Как обычно, проверка переменной__name__в конце примера 1.1 возвра
щает true, только если файл был запущен как самостоятельный сценарий, а не был импортирован как модуль. Если запустить пример как самостоятельный сценарий (например, из командной строки, щелчком на ярлыке или из среды IDLE), будет выполнен программный код теста в теле условной инструкции, который выведет содержимое базы данных в поток стандартного вывода (напомню, что функция print использует этот поток по умолчанию).
Ниже приводится пример запуска сценария из командной строки в ОС Windows. В окне Командная строка (Command Prompt) выполните команду cd, чтобы перейти в каталог со сценарием. На других платформах используйте аналогичную программу-консоль:
...\PP4E\Preview> python initdata.py
bob =>
{‘job’: ‘dev’, ‘pay’: 30000, ‘age’: 42, ‘name’: ‘Bob Smith’}
sue =>
{‘job’: ‘hdw’, ‘pay’: 40000, ‘age’: 45, ‘name’: ‘Sue Jones’} tom =>
{‘job’: None, ‘pay’: 0, ‘age’: 50, ‘name’: ‘Tom’}
Соглашения об именовании файлов
Это наш первый файл (он же «сценарий») с исходными текстами, поэтому здесь необходимо сделать три замечания по использованию примеров из книги:
• Текст .. .\PP4E\Preview> в первой строке предыдущего примера обозначает приглашение к вводу в командной строке и может отличаться в разных платформах. Вам необходимо ввести лишь текст, следующий за этим приглашением (python initdata.py).
• Во всех примерах в этой книге текст системной подсказки к вводу содержит путь к каталогу в загружаемом пакете с примерами, внутри которого должна запускаться указанная команда. При запуске сценария из командной строки убедитесь, что текущим рабочим каталогом является каталог PP4E\Preview. Это может иметь значение для примеров, использующих файлы в рабочем каталоге.