Мэтиз. Изучаем 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.2 Mb.
|
199 Эта строка означает, что файл .txt следует искать в каталоге text_files ; она предпо- лагает, что каталог text_files находится в python_work (так оно и есть). ПРИМЕЧАНИЕ В системе Windows при отображении путей файлов используется об- ратный слеш . Но в своем коде вы можете использовать и обычный слеш . Также можно точно определить местонахождение файла в вашей системе неза- висимо от того, где хранится выполняемая программа. Такие пути называются абсолютными и используются в том случае, если относительный путь не работает. Например, если каталог text_files находится не в python_work , а в другом каталоге (скажем, в каталоге с именем other_files ), то передать open() путь 'text_files/ filename.txt' не получится, потому что Python будет искать указанный каталог только внутри python_work . Чтобы объяснить Python, где следует искать файл, не- обходимо записать полный путь. Абсолютные пути обычно длиннее относительных, поэтому их лучше сохранять в переменных, которые затем передаются open() : file_path = '/home/ehmatthes/other_files/text_files/имя_файла.txt' with open(file_path) as file_object: С абсолютными путями вы сможете читать файлы из любого каталога вашей си- стемы. Пока будет проще хранить файлы в одном каталоге с файлами программ или в каталогах, вложенных в каталог с файлами программ (таких, как text_files из рассмотренного примера). ПРИМЕЧАНИЕ Если вы попытаетесь использовать символ \ в пути, произойдет ошибка, потому что этот символ используется для экранирования служебных символов в строках . Например, в пути 'C:\path\to\file.txt' последовательность \t интерпре- тируется как символ табуляции . Если вам потребуется включить литерал \ в строку, экранируйте каждое вхождение такого символа: 'C:\\path\\to\\file.txt' . Чтение по строкам В процессе чтения файла часто бывает нужно обработать каждую строку. Воз- можно, вы ищете некую информацию в файле или собираетесь каким-то образом изменить текст — например, при чтении файла с метеорологическими данными вы обрабатываете каждую строку, в которой в описании погоды встречается слово «солнечно». Или, допустим, в новостях вы ищете каждую строку с тегом заголовка и заменяете ее специальными элементами форматирования. Для последовательной обработки каждой строки в файле можно воспользоваться циклом for : file_reader.py ❶ filename = 'pi_digits.txt' 200 Глава 10 • Файлы и исключения ❷ with open(filename) as file_object: ❸ for line in file_object: print(line) В точке имя файла, из которого читается информация, сохраняется в перемен- ной filename . Это стандартный прием при работе с файлами: так как переменная filename не представляет конкретный файл (это всего лишь строка, которая со- общает Python, где найти файл), вы сможете легко заменить 'pi_digits.txt' именем другого файла, с которым вы собираетесь работать. После вызова open() объект, представляющий файл и его содержимое, сохраняется в переменной file_ object . Мы снова используем синтаксис with , чтобы поручить Python открывать и закрывать файл в нужный момент. Для просмотра содержимого все строки файла перебираются в цикле for по объекту файла . На этот раз пустых строк оказывается еще больше: 3.1415926535 8979323846 2643383279 Пустые строки появляются из-за того, что каждая строка в текстовом файле завер- шается невидимым символом новой строки. Команда print добавляет свой символ новой строки при каждом вызове, поэтому в результате каждая строка завершается двумя символами новой строки: один прочитан из файла, а другой добавлен коман- дой print . Вызов rstrip() в команде print удаляет лишние пустые строки: filename = 'pi_digits.txt' with open(filename) as file_object: for line in file_object: print(line.rstrip()) Теперь вывод снова соответствует содержимому файла: 3.1415926535 8979323846 2643383279 Создание списка строк по содержимому файла При использовании with объект файла, возвращаемый вызовом open() , доступен только в пределах содержащего его блока with . Если вы хотите, чтобы содержимое файла оставалось доступным за пределами блока with , сохраните строки файла в списке внутри блока и в дальнейшем работайте с полученным списком. Одни части файла можно обработать немедленно, а другие отложить для обработки в будущем. Чтение из файла 201 В следующем примере строки pi_digits .txt сохраняются в списке в блоке with , после чего выводятся за пределами этого блока: filename = 'pi_digits.txt' with open(filename) as file_object: ❶ lines = file_object.readlines() ❷ for line in lines: print(line.rstrip()) В точке метод readlines() последовательно читает каждую строку из файла и сохраняет ее в списке. Список сохраняется в переменной lines , с которой можно продолжить работу после завершения блока with . В точке в простом цикле for выводятся все элементы списка lines . Так как каждый элемент lines соответствует ровно одной строке файла, вывод точно соответствует его содержимому. Работа с содержимым файла После того как файл будет прочитан в память, вы сможете обрабатывать данные так, как считаете нужным. Для начала попробуем построить одну строку со всеми цифрами из файла без промежуточных пропусков: pi_string.py filename = 'pi_digits.txt' with open(filename) as file_object: lines = file_object.readlines() ❶ pi_string = '' ❷ for line in lines: pi_string += line.rstrip() ❸ print(pi_string) print(len(pi_string)) Сначала программа открывает файл и сохраняет каждую строку цифр в списке — точно так же, как это делалось в предыдущем примере. В точке создается пере- менная pi_string для хранения цифр числа «пи». Далее следует цикл, который добавляет к pi_string каждую серию цифр, из которой удаляется символ новой строки . В точке программа выводит строку и ее длину: 3.1415926535 8979323846 2643383279 36 Переменная pi_string содержит пропуски, которые присутствовали в начале каждой строки цифр. Чтобы удалить их, достаточно использовать strip() вместо rstrip() : 202 Глава 10 • Файлы и исключения for line in lines: pi_string += line.strip() print(pi_string) print(len(pi_string)) В итоге мы получаем строку, содержащую значение «пи» с точностью до 30 знаков. Длина строки равна 32 символам, потому что в нее также включается начальная цифра 3 и точка: 3.141592653589793238462643383279 32 ПРИМЕЧАНИЕ Читая данные из текстового файла, Python интерпретирует весь текст в файле как строку . Если вы читаете из текстового файла число и хотите работать с ним в числовом контексте, преобразуйте его в целое число функцией int() или в веще- ственное число функцией float() . Большие файлы: миллион цифр До настоящего момента мы ограничивались анализом текстового файла, кото- рый состоял всего из трех строк, но код этих примеров будет работать и с много большими файлами. Начиная с текстового файла, содержащего значение «пи» до 1 000 000 знаков (вместо 30), вы сможете создать одну строку, которая содержит все эти цифры. Изменять программу вообще не придется — достаточно передать ей другой файл. Также мы ограничимся выводом первых 50 цифр, чтобы не пришлось ждать, пока в терминале не прокрутится миллион знаков: pi_string.py filename = 'pi_million_digits.txt' with open(filename) as file_object: lines = file_object.readlines() pi_string = '' for line in lines: pi_string += line.strip() print(f"{pi_string[:52]}...") print(len(pi_string)) Из выходных данных видно, что строка действительно содержит значение «пи» с точностью до 1 000 000 знаков: 3.14159265358979323846264338327950288419716939937510... 1000002 Python не устанавливает никаких ограничений на длину данных, с которыми вы можете работать. Она ограничивается разве что объемом памяти вашей системы. Чтение из файла 203 ПРИМЕЧАНИЕ Для запуска этой программы (и многих других примеров, при- веденных ниже) необходимо загрузить ресурсы по адресу https://www .nostarch .com/ pythoncrashcourse2e/ Проверка дня рождения Меня всегда интересовало, не встречается ли мой день рождения среди цифр числа «пи»? Воспользуемся только что созданной программой для проверки того, входит ли запись дня рождения пользователя в первый миллион цифр. Для этого можно записать день рождения в виде строки из цифр и посмотреть, присутствует ли эта строка в pi_string : for line in lines: pi_string += line.strip() ❶ birthday = input("Enter your birthday, in the form mmddyy: ") ❷ if birthday in pi_string: print("Your birthday appears in the first million digits of pi!") else: print("Your birthday does not appear in the first million digits of pi.") В точке программа запрашивает день рождения пользователя, а затем в точке проверяет вхождение этой строки в pi_string . Пробуем: Enter your birthdate, in the form mmddyy: 120372 Your birthday appears in the first million digits of pi! Оказывается, мой день рождения встречается среди цифр «пи»! После того, как данные будут прочитаны из файла, вы сможете делать с ними все, что сочтете нужным. УПРАЖНЕНИЯ 10.1. Изучение Python: откройте пустой файл в текстовом редакторе и напишите несколь- ко строк текста о возможностях Python. Каждая строка должна начинаться с фразы «In Python you can…». Сохраните файл под именем learning_python .txt в каталоге, использован- ном для примеров этой главы. Напишите программу, которая читает файл и выводит текст три раза: с чтением всего файла, с перебором строк объекта файла и с сохранением строк в списке с последующим выводом списка вне блока with 10.2. Изучение C: метод replace() может использоваться для замены любого слова в стро- ке другим словом. В следующем примере слово 'dog' заменяется словом 'cat' : >>> message = "I really like dogs." >>> message.replace('dog', 'cat') 'I really like cats.' Прочитайте каждую строку из только что созданного файла learning_python .txt и замените слово Python названием другого языка, например C. Выведите каждую измененную строку на экран. 204 Глава 10 • Файлы и исключения Запись в файл Один из простейших способов сохранения данных — запись в файл. Текст, записан- ный в файл, останется доступным и после закрытия терминала с выводом вашей программы. Вы сможете проанализировать результаты после завершения про- граммы или передать свои файлы другим. Вы также сможете написать программы, которые снова читают сохраненный текст в память и работают с ним. Запись в пустой файл Чтобы записать текст в файл, необходимо вызвать open() со вторым аргументом, который сообщает Python, что вы собираетесь записывать данные в файл. Чтобы увидеть, как это делается, напишем простое сообщение и сохраним его в файле (вместо того, чтобы просто вывести на экран): write_message.py filename = 'programming.txt' ❶ with open(filename, 'w') as file_object: ❷ file_object.write("I love programming.") При вызове open() в этом примере передаются два аргумента . Первый аргумент, как и прежде, содержит имя открываемого файла. Второй аргумент 'w' сообщает Python, что файл должен быть открыт в режиме записи. Файлы можно открывать в режиме чтения ( 'r' ), записи ( 'w' ), присоединения ( 'a' ) или в режиме, допуска- ющем как чтение, так и запись в файл ( 'r+' ). Если аргумент режима не указан, Python по умолчанию открывает файл в режиме только для чтения. Если файл, открываемый для записи, еще не существует, функция open() автома- тически создает его. Будьте внимательны, открывая файл в режиме записи ( 'w' ): если файл существует, то Python уничтожит его данные перед возвращением объ- екта файла. В точке метод write() используется с объектом файла для записи строки в файл. Программа не выводит данные на терминал, но открыв файл programming .txt , вы увидите в нем одну строку: programming.txt I love programming. Этот файл ничем не отличается от любого другого текстового файла на вашем ком- пьютере. Его можно открыть, записать в него новый текст, скопировать/вставить текст и т. д. ПРИМЕЧАНИЕ Python может записывать в текстовые файлы только строковые дан- ные . Если вы захотите сохранить в текстовом файле числовую информацию, данные придется предварительно преобразовать в строки функцией str() . Запись в файл 205 Многострочная запись Функция write() не добавляет символы новой строки в записываемый текст. А это означает, что если вы записываете сразу несколько строк без включения символов новой строки, полученный файл может выглядеть не так, как вы рассчитывали: filename = 'programming.txt' with open(filename, 'w') as file_object: file_object.write("I love programming.") file_object.write("I love creating new games.") Открыв файл programming .txt , вы увидите, что две строки «склеились»: I love programming.I love creating new games. Если включить символы новой строки в команды write() , текст будет состоять из двух строк: filename = 'programming.txt' with open(filename, 'w') as file_object: file_object.write("I love programming.\n") file_object.write("I love creating new games.\n") Результат выглядит так: I love programming. I love creating new games. Для форматирования вывода также можно использовать пробелы, символы табу- ляции и пустые строки по аналогии с тем, как это делалось с выводом на терминал. Присоединение данных к файлу Если вы хотите добавить в файл новые данные вместо того, чтобы перезаписывать существующее содержимое, откройте файл в режиме присоединения. В этом слу- чае Python не уничтожает содержимое файла перед возвращением объекта файла. Все строки, выводимые в файл, будут добавлены в конец файла. Если файл еще не существует, то Python автоматически создаст пустой файл. Изменим программу write_message .py и дополним существующий файл programming . txt новыми данными: write_message.py filename = 'programming.txt' ❶ with open(filename, 'a') as file_object: ❷ file_object.write("I also love finding meaning in large datasets.\n") file_object.write("I love creating apps that can run in a browser.\n") 206 Глава 10 • Файлы и исключения В точке аргумент 'a' используется для открытия файла в режиме присоединения (вместо перезаписи существующего файла). В точке записываются две новые строки, которые добавляются к содержимому programming .txt : programming.txt I love programming. I love creating new games. I also love finding meaning in large datasets. I love creating apps that can run in a browser. В результате к исходному содержимому файла добавляется новый текст. УПРАЖНЕНИЯ 10.3. Гость: напишите программу, которая запрашивает у пользователя его имя. Введенный ответ сохраняется в файле с именем guest .txt 10.4. Гостевая книга: напишите цикл while , который запрашивает у пользователей имена. При вводе каждого имени выведите на экран приветствие и добавьте строку с сообщением в файл с именем guest_book .txt . Проследите за тем, чтобы каждое сообщение размещалось в отдельной строке файла. 10.5. Опрос: напишите цикл while , в котором программа спрашивает у пользователя, по- чему ему нравится программировать. Каждый раз, когда пользователь вводит очередную причину, сохраните текст его ответа в файле. Исключения Для управления ошибками, возникающими в ходе выполнения программы, в Python используются специальные объекты, называемые исключениями. Если при возникновении ошибки Python не знает, что делать дальше, создается объект исключения. Если в программу включен код обработки исключения, то выполне- ние программы продолжится, а если нет — программа останавливается и выводит трассировку с отчетом об исключении. Исключения обрабатываются в блоках try - except . Блок try - except приказывает Python выполнить некоторые действия, но при этом также сообщает, что делать при возникновении исключения. С блоками try - except ваши программы будут работать даже в том случае, если что-то пошло не так. Вместо невразумительной трассировки выводится понятное сообщение об ошибке, которое вы определяете в программе. Обработка исключения ZeroDivisionError Рассмотрим простую ошибку, при которой Python инициирует исключение. Ко- нечно, вы знаете, что деление на ноль невозможно, но мы все же прикажем Python выполнить эту операцию: Исключения 207 division_calculator.py print(5/0) Конечно, из этого ничего не выйдет, поэтому на экран выводятся данные трасси- ровки: Traceback (most recent call last): File "division.py", line 1, in ❶ ZeroDivisionError: division by zero Ошибка, упоминаемая в трассировке , — ZeroDivisionError — является объектом исключения. Такие объекты создаются в том случае, если Python не может выпол- нить ваши распоряжения. Обычно в таких случаях Python прерывает выполнение программы и сообщает тип обнаруженного исключения. Эта информация может использоваться в программе; по сути, вы сообщаете Python, как следует поступить при возникновении исключения данного типа. В таком случае ваша программа будет подготовлена к его появлению. Блоки try-except Если вы предполагаете, что в программе может произойти ошибка, напишите блок try - except для обработки возникающего исключения. Такой блок приказывает Python выполнить некоторый код, а также сообщает, что нужно делать, если при его выполнении произойдет исключение конкретного типа. Вот как выглядит блок try - except для обработки исключений ZeroDivisionError : try: print(5/0) except ZeroDivisionError: print("You can't divide by zero!") Команда print(5/0) , порождающая ошибку, находится в блоке try . Если код в бло- ке try выполнен успешно, то Python пропускает блок except . Если код в блоке try порождает ошибку, то Python ищет блок except с соответствующей ошибкой и выпускает код в этом блоке. В этом примере код блока try порождает ошибку ZeroDivisionError , поэтому Python ищет блок except с описанием того, как следует действовать в такой ситу- ации. При выполнении кода этого блока пользователь видит понятное сообщение об ошибке вместо данных трассировки: You can't divide by zero! Если за кодом try - except следует другой код, то выполнение программы продол- жится, потому что мы объяснили Python, как обрабатывать эту ошибку. В следу- ющем примере обработка ошибки позволяет программе продолжить выполнение. |