Главная страница

Книга Изучаем Python


Скачать 4.68 Mb.
НазваниеКнига Изучаем Python
Дата10.12.2022
Размер4.68 Mb.
Формат файлаpdf
Имя файлаErik_Metiz_Izuchaem_Python_Programmirovanie_igr_vizualizatsia_da.pdf
ТипКнига
#837531
страница24 из 53
1   ...   20   21   22   23   24   25   26   27   ...   53
title.split()
['Alice', 'in', 'Wonderland']
Метод split()
разделяет строку на части по всем позициям, в которых обнаружит пробел, и сохраняет все части строки в элементах списка. В результате создается список слов, входящих в строку (впрочем, вместе с некоторыми словами могут храниться знаки препинания). Для подсчета слов в книге мы воспользуемся вызо- вом split()
для всего текста, а затем подсчитаем элементы списка, чтобы получить примерное количество слов в тексте:
filename = 'alice.txt'
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry, the file " + filename + " does not exist."
print(msg)
else:
# Подсчет приблизительного количества строк в файле.
 words = contents.split()
 num_words = len(words)
 print("The file " + filename + " has about " + str(num_words) +
" words.")
Затем я переместил файл alice .txt в правильный каталог, чтобы код в блоке try был выполнен без ошибок. В точке  программа загружает текст в переменную contents
, которая теперь содержит весь текст в виде одной длинной строки и ис- пользует метод split()
для получения списка всех слов в книге. Запрашивая длину этого списка при помощи функции len()
, мы получаем неплохое при- ближенное значение количества слов в исходной строке . В точке  выводится сообщение с количеством слов, найденных в файле. Этот код помещен в блок else
, потому что он должен выводиться только в случае успешного выполнения блока try
. Выходные данные программы сообщают, сколько слов содержит файл alice .txt
:
The file alice.txt has about 29461 words.
Количество слов немного завышено, потому что в нем учитывается дополнительная информация, включенная в текстовый файл издателем, но в целом оно довольно точно оценивает длину «Алисы в Стране чудес».

Исключения 201
Работа с несколькими файлами
Добавим еще несколько файлов с книгами для анализа. Но для начала переместим основной код программы в функцию с именем count_words()
. Это упростит про- ведение анализа для нескольких книг:
word_count.py
def count_words(filename):

"""Подсчет приблизительного количества строк в файле."""
try:
with open(filename) as f_obj:
contents = f_obj.read()
except FileNotFoundError:
msg = "Sorry, the file " + filename + " does not exist."
print(msg)
else:
# Подсчет приблизительного количества строк в файле.
words = contents.split()
num_words = len(words)
print("The file " + filename + " has about " + str(num_words) +
" words.")
filename = 'alice.txt'
count_words(filename)
Бульшая часть кода не изменилась. Мы просто снабдили код отступом и пере- местили его в тело count_words()
. Кроме того, комментарий был преобразован в строку документации .
Теперь мы можем написать простой цикл для подсчета слов в любом тексте, который нужно проанализировать. Для этого имена анализируемых файлов со- храняются в списке, после чего для каждого файла в списке вызывается функ- ция count_words()
. Мы попробуем подсчитать слова в «Алисе в Стране чудес»,
«Сиддхартхе», «Моби Дике» и «Маленьких женщинах» — все эти книги есть в свободном доступе. Я намеренно не стал копировать файл siddhartha .txt в каталог с программой word_count .py
, чтобы выяснить, насколько хорошо наша программа справляется с отсутствием файла:
def count_words(filename):
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words(filename)
Отсутствие файла siddhartha .txt не влияет на выполнение программы:
The file alice.txt has about 29461 words.
Sorry, the file siddhartha.txt does not exist.
The file moby_dick.txt has about 215136 words.
The file little_women.txt has about 189079 words.

202 Глава 10 • Файлы и исключения
Использование блока try
- except в этом примере дает два важных преимущества: программа ограждает пользователя от вывода трассировки и продолжает выполне- ние, анализируя тексты, которые ей удается найти. Если бы в программе не пере- хватывалось исключение
FileNotFoundError
, инициированное из-за отсутствия siddhartha .txt
, то пользователь увидел бы полную трассировку, а работа программы прервалась бы после попытки подсчитать слова в тексте «Сиддхартхи»; до анализа
«Моби Дика» или «Маленьких женщин» дело не дошло бы.
Ошибки без уведомления пользователя
В предыдущем примере мы сообщили пользователю о том, что один из файлов ока- зался недоступен. Тем не менее вы не обязаны сообщать о каждом обнаруженном исключении. Иногда при возникновении исключения программа должна просто проигнорировать сбой и продолжать работу, словно ничего не произошло. Для этого блок try пишется так же, как обычно, но в блоке except вы явно приказыва- ете Python не предпринимать никаких особых действий в случае ошибки. В языке
Python существует команда pass
, с которой блок ничего не делает:
def count_words(filename):
"""Подсчет приблизительного количества строк в файле."""
try:
except FileNotFoundError:
 pass else:
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
count_words(filename)
Единственное отличие этого листинга от предыдущего — команда pass в точке .
Теперь при возникновении ошибки
FileNotFoundError выполняется код в блоке except
, но при этом ничего не происходит. Программа не выдает данные трасси- ровки и вообще никакие результаты, указывающие на возникновение ошибки.
Пользователи получают данные о количестве слов во всех существующих файлах, однако ничто не сообщает о том, что какой-то файл не был найден:
The file alice.txt has about 29461 words.
The file moby_dick.txt has about 215136 words.
The file little_women.txt has about 189079 words.
Команда pass также может служить временным заполнителем. Она напоминает, что в этот конкретный момент выполнения вашей программы вы решили ниче- го не предпринимать, хотя, возможно, сделаете что-то позднее. Например, эта программа может записать все имена отсутствующих файлов в файл с именем missing_files .txt
. Пользователи этот файл не увидят, но создатель программы сможет прочитать его и разобраться с отсутствующими текстами.

Исключения 203
О каких ошибках нужно сообщать?
Как определить, в каком случае следует сообщить об ошибке пользователю, а когда можно просто проигнорировать ее незаметно для пользователя? Если пользователь знает, с какими текстами должна работать программа, вероятно, он предпочтет по- лучить сообщение, объясняющее, почему некоторые тексты были пропущены при анализе. Пользователь ожидает увидеть какие-то результаты, но не знает, какие книги должны быть проанализированы? Возможно, ему и не нужно знать о недо- ступности каких-то файлов. Лишняя информация только сделает вашу программу менее удобной для пользователя. Средства обработки ошибок Python позволяют достаточно точно управлять тем, какой объем информации следует предоставить пользователю.
Хорошо написанный, правильно протестированный код редко содержит внутрен- ние ошибки (например, синтаксические или логические). Но в любой ситуации, в которой ваша программа зависит от внешних факторов (пользовательского ввода, существования файла, доступности сетевого подключения), существует риск воз- никновения исключения. С накоплением практического опыта вы начнете видеть, в каких местах программы следует разместить блоки обработки исключений и сколько информации предоставлять пользователям о возникающих ошибках.
УПРАЖНЕНИЯ
10-6 . Сложение: при вводе числовых данных часто встречается типичная проблема: поль- зователь вводит текст вместо чисел . При попытке преобразовать данные в int происходит исключение TypeError . Напишите программу, которая запрашивает два числа, складывает их и выводит результат . Перехватите исключение TypeError, если какое-либо из входных значений не является числом, и выведите удобное сообщение об ошибке . Протестируйте свою программу: сначала введите два числа, а потом введите текст вместо одного из чисел .
10-7 . Калькулятор: заключите код из упражнения 10-6 в цикл while, чтобы пользователь мог продолжать вводить числа, даже если он допустил ошибку и ввел текст вместо числа .
10-8 . Кошки и собаки: создайте два файла с именами cats .txt и dogs .txt . Сохраните минимум три клички кошек в первом файле и три клички собак во втором . Напишите программу, которая пытается прочитать эти файлы и выводит их содержимое на экран . Заключите свой код в блок try-except для перехвата исключения FileNotFoundError и вывода понятного сообщения об отсутствии файла . Переместите один из файлов в другое место файловой системы; убедитесь в том, что код блока except выполняется, как и положено .
10-9 . Ошибки без уведомления: измените блок except из упражнения 10-8 так, чтобы при отсутствии файла программа продолжала работу, не уведомляя пользователя о проблеме .
10-10 . Частые слова: зайдите на сайт проекта «Гутенберг» (http://gutenberg .org/) и найдите несколько книг для анализа . Загрузите текстовые файлы этих произведений или скопируй- те текст из браузера в текстовый файл на вашем компьютере .
Для подсчета количества вхождений слова или выражения в строку можно воспользовать- ся методом count() . Например, следующий код подсчитывает количество вхождений ‘row’ в строке:
>>> line = "Row, row, row your boat"
>>> line.count('row')
2
>>> line.lower().count('row')
3

204 Глава 10 • Файлы и исключения
Обратите внимание: преобразование строки к нижнему регистру функцией lower() позволя- ет найти все вхождения искомого слова независимо от регистра .
Напишите программу, которая читает файлы из проекта «Гутенберг» и определяет количе- ство вхождений слова ‘the’ в каждом тексте .
Сохранение данных
Многие ваши программы будут запрашивать у пользователя информацию. Напри- мер, пользователь может вводить настройки для компьютерной игры или данные для визуального представления. Чем бы ни занималась ваша программа, инфор- мация, введенная пользователем, будет сохраняться в структурах данных (таких, как списки или словари). Когда пользователь закрывает программу, введенную им информацию почти всегда следует сохранять на будущее. Простейший способ сохранения данных основан на использовании модуля json
Модуль json обеспечивает запись простых структур данных Python в файл и за- грузку данных из файла при следующем запуске программы. Модуль json также может использоваться для обмена данными между программами Python. Более того, формат данных JSON не привязан к Python, поэтому данные в этом формате можно передавать программам, написанным на многих других языках програм- мирования. Это полезный и универсальный формат, который к тому же легко изучается.
ПРИМЕЧАНИЕ
Формат JSON (JavaScript Object Notation) был изначально разработан для JavaScript . Впрочем, с того времени он стал использоваться во многих языках, включая Python .
Функции json .dump() и json .load()
Напишем короткую программу для сохранения набора чисел и другую программу, которая будет читать эти числа обратно в память. Первая программа использует функцию json.dump()
, а вторая — функцию json.load()
Функция json.dump()
получает два аргумента: сохраняемые данные и объект фай- ла, используемый для сохранения. В следующем примере json.dump()
используется для сохранения списка чисел:
number_writer.py
import json numbers = [2, 3, 5, 7, 11, 13]
 filename = 'numbers.json'
 with open(filename, 'w') as f_obj:
 json.dump(numbers, f_obj)
Программа импортирует модуль json и создает список чисел для работы. В точке  выбирается имя файла для хранения списка. Обычно для таких файлов принято использовать расширение
.json
, указывающее, что данные в файле хранятся в фор-

Сохранение данных 205
мате JSON. Затем файл открывается в режиме записи, чтобы модуль json мог запи- сать в него данные . В точке  функция json.dump()
используется для сохранения списка numbers в файле numbers .json
Программа ничего не выводит, но давайте откроем файл numbers .json и посмотрим на его содержимое. Данные хранятся в формате, очень похожем на код Python:
[2, 3, 5, 7, 11, 13]
А теперь напишем следующую программу, которая использует json.load()
для чтения списка обратно в память:
number_reader.py
import json
 filename = 'numbers.json'
 with open(filename) as f_obj:
 numbers = json.load(f_obj)
print(numbers)
В точке  для чтения данных используется тот же файл, в который эти данные были записаны. На этот раз файл открывается в режиме чтения, потому что Python нужно только прочитать данные из файла . В точке  функция json.load()
ис- пользуется для загрузки информации из numbers .json
; эта информация сохраняется в переменной numbers
Наконец, программа выводит прочитанный список. Как видите, этот тот же список, который был создан в программе number_writer .py
:
[2, 3, 5, 7, 11, 13]
Модуль json позволяет организовать простейший обмен данными между про- граммами.
Сохранение и чтение данных, сгенерированных пользователем
Сохранение с использованием модуля json особенно полезно при работе с данны- ми, сгенерированными пользователем, потому что без сохранения эта информа- ция будет потеряна при остановке программы. В следующем примере программа запрашивает у пользователя имя при первом запуске программы и «вспоминает» его при повторных запусках.
Начнем с сохранения имени пользователя:
remember_me.py
import json
 username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
 json.dump(username, f_obj)
 print("We'll remember you when you come back, " + username +
"!")

206 Глава 10 • Файлы и исключения
В точке  программа запрашивает имя пользователя для сохранения. Затем вы- зывается функция json.dump()
, которой передается имя пользователя и объект файла; функция сохраняет имя пользователя в файле . Далее выводится сообще- ние о том, что имя пользователя было сохранено :
What is your name? Eric
We'll remember you when you come back, Eric!
А теперь напишем другую программу, которая приветствует пользователя по ранее сохраненному имени:
greet_user.py
import json filename = 'username.json'
with open(filename) as f_obj:
 username = json.load(f_obj)
 print("Welcome back, " + username + "!")
В точке  вызов json.load()
читает информацию из файла username .json в пере- менную username
. После того как данные будут успешно прочитаны, мы можем поприветствовать пользователя по имени :
Welcome back, Eric!
Теперь эти две программы необходимо объединить в один файл. Когда пользова- тель запускает remember_me .py
, программа должна взять имя пользователя из памя- ти, если это возможно; соответственно, программа начинается с блока try
, который пытается прочитать имя пользователя. Если файл username .json не существует, блок except запросит имя пользователя и сохранит его в username .json на будущее:
remember_me.py
import json
# Программа загружает имя пользователя, если оно было сохранено ранее.
# В противном случае она запрашивает имя пользователя и сохраняет его.
filename = 'username.json'
try:
 with open(filename) as f_obj:
 username = json.load(f_obj)
 except FileNotFoundError:
 username = input("What is your name? ")
 with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
else:
print("Welcome back, " + username + "!")
Никакого нового кода здесь нет; просто блоки кода из двух предыдущих приме- ров были объединены в один файл. В точке  программа пытается открыть файл username .json
. Если файл существует, программа читает имя пользователя в па- мять  и выводит сообщение, приветствующее пользователя, в блоке else
. Если

Сохранение данных 207
программа запускается впервые, то файл username .json не существует, и происходит исключение
FileNotFoundError
. Python переходит к блоку except
, в котором пользователю предлагается ввести имя . Затем программа вызывает json.dump()
для сохранения имени пользователя и выводит приветствие .
Какой бы блок ни выполнялся, результатом является имя пользователя и соот- ветствующее сообщение. При первом запуске программы результат выглядит так:
What is your name? Eric
We'll remember you when you come back, Eric!
Если же программа уже была выполнена хотя бы один раз, результат будет таким:
Welcome back, Eric!
Рефакторинг
Часто возникает типичная ситуация: код работает, но вы понимаете, что его струк- туру можно усовершенствовать, разбив его на функции, каждая из которых ре- шает свою конкретную задачу. Этот процесс называется рефакторингом (или переработкой). Рефакторинг делает ваш код более чистым, понятным и простым в расширении.
В процессе рефакторинга remember_me .py мы можем переместить основную часть логики в одну или несколько функций. Основной задачей remember_me .py является вывод приветствия для пользователя, поэтому весь существующий код будет пере- мещен в функцию greet_user()
:
remember_me.py
import json def greet_user():

"""Приветствует пользователя по имени."""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
username = input("What is your name? ")
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
else:
print("Welcome back, " + username + "!")
greet_user()
С переходом на функцию комментарии дополняются строкой документации, кото- рая описывает работу кода в текущей версии . Код становится немного чище, но функция greet_user()
не только приветствует пользователя — она также загружает хранимое имя пользователя, если оно существует, и запрашивает новое имя, если оно не было сохранено ранее.

208 Глава 10 • Файлы и исключения
Переработаем функцию greet_user()
, чтобы она не решала столько разных задач.
Начнем с перемещения кода загрузки хранимого имени пользователя в отдельную функцию:
import json def get_stored_username():

"""Получает хранимое имя пользователя, если оно существует."""
filename = 'username.json'
try:
with open(filename) as f_obj:
username = json.load(f_obj)
except FileNotFoundError:
 return None else:
return username def greet_user():
"""Приветствует пользователя по имени."""
username = get_stored_username()
 if username:
print("Welcome back, " + username + "!")
else:
username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
print("We'll remember you when you come back, " + username + "!")
greet_user()
Новая функция get_stored_username()
имеет четкое предназначение, изложенное в строке документации . Эта функция читает и возвращает сохраненное имя пользователя, если его удается найти. Если файл username .json не существует, то функция возвращает
None
. И это правильно: функция должна возвращать либо ожидаемое значение, либо
None
. Это позволяет провести простую проверку возвращаемого значения функции. В точке  программа выводит приветствие для пользователя, если попытка получения имени пользователя была успешной; в противном случае программа запрашивает новое имя пользователя.
Из функции greet_user()
стоит вынести еще один блок кода. Если имя пользова- теля не существует, то код запроса нового имени должен размещаться в функции, специализирующейся на решении этой задачи:
import json def get_stored_username():
"""Получает хранимое имя пользователя, если оно существует."""
def get_new_username():
"""Запрашивает новое имя пользователя."""
username = input("What is your name? ")
filename = 'username.json'
with open(filename, 'w') as f_obj:
json.dump(username, f_obj)
return username

Итоги
1   ...   20   21   22   23   24   25   26   27   ...   53


написать администратору сайта