Изучаем Python Эрик Метиз. Crash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g
Скачать 6.19 Mb.
|
my_cars.py ❶ import car ❷ my_beetle = car.Car('volkswagen', 'beetle', 2019) print(my_beetle.get_descriptive_name()) ❸ my_tesla = car.ElectricCar('tesla', 'roadster', 2019) print(my_tesla.get_descriptive_name()) В точке импортируется весь модуль car , после чего программа обращается к нуж- ным классам с использованием синтаксиса имя_модуля имя_класса. В точке сно- ва создается экземпляр Volkswagen Beetle, а в точке — экземпляр Tesla Roadster. Импортирование классов 191 Импортирование всех классов из модуля Для импортирования всех классов из модуля используется следующий синтаксис: from имя_модуля import * Использовать этот способ не рекомендуется по двум причинам. Прежде всего, бывает полезно прочитать команды import в начале файла и получить четкое пред- ставление о том, какие классы используются в программе, а при таком подходе неясно, какие классы из модуля нужны программе. Также возможны конфликты с именами в файле. Если вы случайно импортируете класс с именем, уже при- сутствующим в файле, в программе могут возникнуть коварные ошибки. Почему я привожу описание этого способа? Хотя использовать его не рекомендуется, ско- рее всего, вы встретите его в коде других разработчиков. Итак, если вам нужно импортировать большое количество классов из модуля, лучше импортировать весь модуль и воспользоваться синтаксисом имя_модуля имя_класса. Хотя вы не видите перечень всех используемых классов в начале файла, по крайней мере ясно видно, где модуль используется в программе. Также предотвращаются потенциальные конфликты имен, которые могут возникнуть при импортировании каждого класса в модуле. Импортирование модуля в модуль Иногда классы приходится распределять по нескольким модулям, чтобы избежать чрезмерного разрастания одного файла и хранения несвязанных классов в одном модуле. При хранении классов в нескольких модулях может оказаться, что один класс из одного модуля зависит от класса из другого модуля. В таких случаях не- обходимый класс можно импортировать в первый модуль. Допустим, класс Car хранится в одном модуле, а классы ElectricCar и Battery — в другом. Мы создадим новый модуль с именем electric_car .py (он заменит файл electric_car .py , созданный ранее) и скопируем в него только классы Battery и ElectricCar : electric_car.py """Набор классов для представления электромобилей.""" ❶ from car import Car class Battery(): class ElectricCar(Car): Классу ElectricCar необходим доступ к классу-родителю Car , поэтому класс Car импортируется прямо в модуль в точке . Если вы забудете вставить эту команду, 192 Глава 9 • Классы при попытке создания экземпляра ElectricCar произойдет ошибка. Также необхо- димо обновить модуль Car , чтобы он содержал только класс Car : car.py """Простая модель автомобиля.""" class Car(): Теперь вы можете импортировать классы из каждого модуля по отдельности и соз- дать ту разновидность машины, которая вам нужна: my_cars.py ❶ from car import Car from electric_car import ElectricCar my_beetle = Car('volkswagen', 'beetle', 2019) print(my_beetle.get_descriptive_name()) my_tesla = ElectricCar('tesla', 'roadster', 2019) print(my_tesla.get_descriptive_name()) В точке класс Car импортируется из своего модуля, а класс ElectricCar — из сво- его. После этого создаются экземпляры обоих разновидностей. Вывод показывает, что экземпляры были созданы правильно: 2019 Volkswagen Beetle 2019 Tesla Roadster Использование псевдонимов Как было показано в главе 8, псевдонимы весьма полезны при использовании мо- дулей для организации кода проектов. Псевдонимы также могут использоваться и при импортировании классов. Для примера возьмем программу, которая должна создать группу экземпляров элек- трических машин. Многократно вводить (и читать) имя ElectricCar будет очень утомительно. Имени ElectricCar можно назначить псевдоним в команде import : from electric_car import ElectricCar as EC С этого момента вы сможете использовать этот псевдоним каждый раз, когда вам потребуется создать экземпляр ElectricCar : my_tesla = EC('tesla', 'roadster', 2019) Выработка рабочего процесса Как видите, Python предоставляет много возможностей структурирования кода в крупных проектах. Вы должны знать все эти возможности, чтобы найти удачные Стандартная библиотека Python 193 способы организации своих проектов, а также лучше понимать код других раз- работчиков. На первых порах постарайтесь поддерживать простую структуру своего кода. По- пробуйте разместить весь код в одном файле, и только когда все заработает, переме- стите классы в отдельные модули. Если вам нравится схема взаимодействия между модулями и файлами, попробуйте сохранить классы в модулях в начале работы над проектом. Найдите подход, при котором у вас получается работоспособный код, и двигайтесь дальше. УПРАЖНЕНИЯ 9.10. Импортирование класса Restaurant: возьмите последнюю версию класса Restaurant и сохраните ее в модуле. Создайте отдельный файл, импортирующий класс Restaurant Создайте экземпляр Restaurant и вызовите один из методов Restaurant , чтобы показать, что команда import работает правильно. 9.11. Импортирование класса Admin: начните с версии класса из упражнения 9.8 (с. 186). Сохраните классы User , Privileges и Admin в одном модуле. Создайте отдельный файл, соз- дайте экземпляр Admin и вызовите метод show_privileges() , чтобы показать, что все рабо- тает правильно. 9.12. Множественные модули: сохраните класс User в одном модуле, а классы Privileges и Admin в другом модуле. В отдельном файле создайте экземпляр Admin и вызовите метод show_privileges() , чтобы показать, что все работает правильно. Стандартная библиотека Python Стандартная библиотека Python представляет собой набор модулей, включаемых в каждую установленную копию Python. Сейчас вы уже примерно понимаете, как работают классы, и можете начать использовать модули, написанные другими программистами. Чтобы использовать любую функцию или класс из стандартной библиотеки, достаточно включить простую команду import в начало файла. Для примера рассмотрим модуль random , который может пригодиться для моделирова- ния многих реальных ситуаций. В частности, модуль random содержит интересную функцию randint() . Эта функ- ция получает два целочисленных аргумента и возвращает случайно выбранное целое число в диапазоне, определяемом этими двумя числами (включительно). В следующем примере генерируется случайное число в диапазоне от 1 до 6: >>> from random import randint >>> randint(1, 6) 3 Другая полезная функция, choice() , получает список или кортеж и возвращает случайно выбранный элемент: 194 Глава 9 • Классы >>> from random import choice >>> players = ['charles', 'martina', 'michael', 'florence', 'eli'] >>> first_up = choice(players) >>> first_up 'florence' Модуль random не должен использоваться при построении приложений, связанных с безопасностью, но его возможностей достаточно для многих интересных и увле- кательных проектов. ПРИМЕЧАНИЕ Модули также можно загружать из внешних источников . Соответству- ющие примеры встретятся вам в части II, в которой для завершения работы над про- ектами мы будем использовать внешние модули . УПРАЖНЕНИЯ 9.13. Кубики: создайте класс Die с одним атрибутом sides , который имеет значение по умолчанию 6. Напишите метод roll_die() для вывода случайного числа от 1 до количества граней на кубике. Создайте экземпляр, представляющий 6-гранный кубик, и смоделируйте 10 бросков. Создайте экземпляры, представляющие 10- и 20-гранный кубик. Смоделируйте 10 бросков каждого кубика. 9.14. Лотерея: создайте список или кортеж, содержащий серию из 10 чисел и 5 букв. Слу- чайным образом выберите 4 числа или буквы из списка. Выведите сообщение о том, что билет, содержащий эту комбинацию из четырех цифр или букв, является выигрышным. 9.15. Анализ лотереи: напишите цикл, который проверяет, насколько сложно выиграть в смоделированной вами лотерее. Создайте список или кортеж с именем my_ticket . Напи- шите цикл, который продолжает генерировать комбинации до тех пор, пока не выпадет вы- игрышная комбинация. Выведите сообщение с информацией о том, сколько выполнений цикла понадобилось для получения выигрышной комбинации. 9.16. Модуль недели: для знакомства со стандартной библиотекой Python отлично подой- дет сайт Python Module of the Week. Откройте сайт http://pymotw .com/ и просмотрите оглав- ление. Найдите модуль, который покажется вам интересным; прочитайте его описание или изучите документацию по модулю random Оформление классов В стилевом оформлении классов есть несколько моментов, о которых стоит упо- мянуть отдельно, особенно с усложнением ваших программ. Имена классов должны записываться в «верблюжьем» регистре: первая буква каждого слова записывается в верхнем регистре, слова не разделяются пробелами. Имена экземпляров и модулей записываются в нижнем регистре с разделением слов символами подчеркивания. Каждый класс должен иметь строку документации, следующую сразу же за опреде- лением класса. Строка документации должна содержать краткое описание того, что Итоги 195 делает класс, и в ней должны соблюдаться те же соглашения по форматированию, которые вы использовали при написании строк документации в функциях. Каждый модуль также должен содержать строку документации с описанием возможных применений классов в модуле. Пустые строки могут использоваться для структурирования кода, но злоупотреб- лять ими не стоит. В классах можно разделять методы одной пустой строкой, а в модулях для разделения классов можно использовать две пустые строки. Если вам потребуется импортировать модуль из стандартной библиотеки и модуль из библиотеки, написанной вами, начните с команды import для модуля стандарт- ной библиотеки. Затем добавьте пустую строку и команду import для модуля, написанного вами. В программах с несколькими командами import выполнение этого соглашения поможет понять, откуда берутся разные модули, использованные в программе. Итоги В этой главе вы узнали, как написать собственные классы. Вы научились хранить информацию в классе с использованием атрибутов и наделять свои классы нужным поведением. Вы узнали, как написать методы __init__() для создания экземпляров ваших классов с нужными значениями атрибутов и как изменять атрибуты экзем- пляров напрямую и через методы. Также было показано, что наследование может упростить создание логически связанных классов и что экземпляры одного класса могут использоваться как атрибуты другого класса для упрощения кода классов. Вы узнали, что хранение классов в модулях и импортирование необходимых классов в файлы, где они будут использоваться, улучшает организацию проектов. Вы познакомились со стандартной библиотекой Python и рассмотрели пример, основанный на модуле random . Наконец, вы научились оформлять свои классы с использованием общепринятых соглашений Python. В главе 10 вы научитесь работать с файлами и сохранять результаты работы, вы- полненной в программе. Также будут рассмотрены исключения — экземпляры специального класса Python, предназначенного для передачи информации о воз- никающих ошибках. 10 Файлы и исключения Вы уже овладели основными навыками, необходимыми для создания хорошо структурированных и удобных в использовании программ; теперь пора подумать о том, как сделать ваши программы еще более удобными и полезными. В этой главе вы научитесь работать с файлами, чтобы ваши программы могли быстро анализи- ровать большие объемы данных. Вы научитесь обрабатывать ошибки, чтобы возникновение аномальных ситуаций не приводило к аварийному завершению ваших программ. Мы рассмотрим исклю- чения — специальные объекты, которые создаются для управления ошибками, воз- никающими во время выполнения программ Python. Также будет описан модуль json , позволяющий сохранять пользовательские данные, чтобы они не терялись по завершении работы программы. Работа с файлами и сохранение данных упрощают использование ваших про- грамм. Пользователь сам выбирает, какие данные и когда нужно вводить. Он может запустить вашу программу, выполнить некоторую работу, потом закрыть программу и позднее продолжить работу с того момента, на котором он прервался. Умение обрабатывать исключения поможет справиться с такими ситуациями, как отсутствие нужных файлов, а также другими проблемами, приводящими к сбою программ. Обработка исключений повысит устойчивость ваших программ при работе с некорректными данными — появившимися как из-за случайных ошибок, так и в результате злонамеренных попыток взлома ваших программ. Материал, представленный в этой главе, сделает ваши программы более практичными, удоб- ными и надежными. Чтение из файла Гигантские объемы данных доступны в текстовых файлах. В них могут храниться погодные данные, социально-экономическая информация, литературные произ- ведения и многое другое. Чтение из файла особенно актуально для приложений, предназначенных для анализа данных, но оно также может пригодиться в любой ситуации, требующей анализа или изменения информации, хранящейся в файле. Например, программа может читать содержимое текстового файла и переписывать его с форматированием, рассчитанным на отображение информации в браузере. Чтение из файла 197 Работа с информацией в текстовом файле начинается с чтения данных в память. Вы можете прочитать все содержимое файла или же читать данные по строкам. Чтение всего файла Для начала нам понадобится файл с несколькими строками текста. Пусть это будет файл с числом «пи» с точностью до 30 знаков, по 10 знаков на строку: pi_digits.txt 3.1415926535 8979323846 2643383279 Чтобы опробовать эти примеры, либо введите данные в редакторе и сохраните файл с именем pi_digits .txt , либо загрузите файл из ресурсов книги на странице https:// www .nostarch .com/pythoncrashcourse2e/ . Сохраните файл в каталоге, в котором будут храниться программы этой главы. Следующая программа открывает этот файл, читает его и выводит содержимое на экран: file_reader.py with open('pi_digits.txt') as file_object: contents = file_object.read() print(contents) В первой строке этой программы многое заслуживает вашего внимания. Начнем с функции open() . Чтобы выполнить любые операции с файлом — даже просто вывести его содержимое, — сначала необходимо открыть файл. Функция open() получает один аргумент: имя открываемого файла. Python ищет файл с указанным именем в каталоге, в котором находится файл текущей программы. В данном при- мере выполняется программа file_reader .py , поэтому Python ищет файл pi_digits .txt в каталоге, в котором хранится file_reader .py . Функция open() возвращает объект, представляющий файл. В данном случае open('pi_digits.txt') возвращает объ- ект, представляющий файл pi_digits .txt . Python сохраняет этот объект в переменной file_object , с которой мы будем работать позднее в программе. Конструкция с ключевым словом with закрывает файл после того, как надобность в нем отпадет. Обратите внимание: в этой программе есть вызов open() , но нет вызова close() . Файлы можно открывать и закрывать явными вызовами open() и close() ; но если из-за ошибки в программе команда close() останется невыпол- ненной, то файл не будет закрыт. На первый взгляд это не страшно, но некоррект- ное закрытие файлов может привести к потере или порче данных. А если функция close() будет вызвана слишком рано, программа попытается работать с закрытым (то есть недоступным) файлом, что приведет к новым ошибкам. Не всегда можно заранее определить, когда нужно закрывать файл, но с приведенной конструкцией Python сделает это за вас. Вам остается лишь открыть файл и работать с ним так, 198 Глава 10 • Файлы и исключения как требуется, надеясь на то, что Python закроет его автоматически при завершении блока with После того как в программе появится объект, представляющий файл pi_digits .txt , во второй строке программы используется метод read() , который читает все содер- жимое файла и сохраняет его в одной длинной строке в переменной contents . При выводе значения contents на экране появляется все содержимое файла : 3.1415926535 8979323846 2643383279 Единственное различие между выводом и исходным файлом — лишняя пустая строка в конце вывода. Откуда она взялась? Метод read() возвращает ее при чте- нии, если достигнут конец файла. Если вы хотите удалить лишнюю пустую строку, включите вызов rstrip() в вызов print() : with open('pi_digits.txt') as file_object: contents = file_object.read() print(contents.rstrip()) Напомним, что метод rstrip() удаляет все пропуски в конце строки. Теперь вывод точно соответствует содержимому исходного файла: 3.1415926535 8979323846 2643383279 Пути к файлам Если передать функции open() простое имя файла, такое как pi_digits .txt , Python ищет файл в том каталоге, в котором находится файл, выполняемый в настоящий момент (то есть файл программы .py ). В некоторых случаях (в зависимости от того, как организованы ваши рабочие файлы) открываемый файл может и не находиться в одном каталоге с файлом программы. Например, файл программы может находиться в каталоге python_work ; в каталоге python_work создается другой каталог с именем text_files для текстовых файлов, с которыми работает программа. И хотя папка text_files находится в python_ work , простая передача open() имени файла из text_files не подойдет, потому что Python произведет поиск файла в python_work и на этом остановится; поиск не будет продолжен во вложенном каталоге text_files . Чтобы открыть файлы из каталога, от- личного от того, в котором хранится файл программы, необходимо указать путь — то есть приказать Python искать файлы в конкретном месте файловой системы. Так как каталог text_files находится в python_work , для открытия файла из text_files можно воспользоваться относительным путем. Относительный путь приказывает Python искать файлы в каталоге, который задается относительно каталога, в ко- тором находится текущий файл программы. Например, это может выглядеть так: with open('text_files/имя_файла.txt') as file_object: |