Сборник. Сборник упражнений
Скачать 1.68 Mb.
|
Глава 15 Файлы и исключения Упражнение 149. Отображаем заголовок файла ## # Показываем первые 10 строк файла, имя которого передано в качестве аргумента командной строки # import sys NUM_LINES = 10 # Проверяем, что программе был передан только один аргумент командной строки if len(sys.argv) != 2: print("Передайте имя файла в качестве аргумента командной строки.") quit() try: # Открываем файл на чтение inf = open(sys.argv[1], "r") # Читаем первую строку из файла line = inf.readline() # Продолжаем цикл, пока не прочитаем 10 строк или не дойдем до конца файла count = 0 while count < NUM_LINES and line != "": # Удаляем символ конца строки и увеличиваем счетчик line = line.rstrip() count = count + 1 # Отображаем строку print(line) # Читаем следующую строку из файла line = inf.readline() # Закрываем файл inf.close() По вызову функции quit программа мгновенно завершается. 220 Решения except IOError: # Отображаем ошибку, если с чтением из файла возникли проблемы print("Ошибка при доступе к файлу.") Упражнение 150. Отображаем конец файла ## # Показываем первые 10 строк файла, имя которого передано в качестве аргумента командной строки # import sys NUM_LINES = 10 # Проверяем, что программе был передан только один аргумент командной строки if len(sys.argv) != 2: print("Передайте имя файла в качестве аргумента командной строки.") quit() try: # Открываем файл на чтение inf = open(sys.argv[1], "r") # Читаем файл, сохраняя NUM_LINES последних строк lines = [] for line in inf: # Добавляем последнюю прочитанную строку к концу списка lines.append(line) # Если у нас накопилось больше NUM_LINES строк, удаляем самую старую if len(lines) > NUM_LINES: lines.pop(0) # Закрываем файл inf.close() except: print("Ошибка при доступе к файлу.") quit() # Отображаем последние строки из файла for line in lines: print(line, end="") Упражнение 151. Сцепляем файлы ## # Сцепляем два или более файлов и отображаем результат # import sys Файлы и исключения 221 # Убедимся, что хотя бы один параметр был передан в качестве аргумента командной строки if len(sys.argv) == 1: print("Нужно передать программе хотя бы один аргумент.") quit() # Обрабатываем все файлы, имена которых были переданы в качестве аргументов for i in range(1, len(sys.argv)): fname = sys.argv[i] try: # Открываем текущий файл на чтение inf = open(fname, "r") # Отображаем файл for line in inf: print(line, end="") # Закрываем файл inf.close() except: # Отображаем предупреждение, но не завершаем выполнение программы print("Невозможно открыть/отобразить файл", fname) Упражнение 156. Сумма чисел ## # Подсчитаем сумму переданных пользователем чисел, не считая нечислового ввода # # Запрашиваем у пользователя первое число line = input("Введите число: ") total = 0 # Продолжаем запрашивать числа, пока пользователь не оставит ввод пустым while line != "": try: # Пытаемся конвертировать значение в число num = float(line) # Если все прошло успешно, прибавляем введенное число к общей сумме total = total + num print("Сумма сейчас составляет", total) except ValueError: # Отображаем предупреждение и переходим к следующему вводу print("Это было не число") # Запрашиваем следующее число line = input("Введите число: ") # Отображаем сумму print("Общая сумма:", total) Элемент с индексом 0 в списке sys. argv является ссылкой на исполняе- мый файл Python. Поэтому наш цикл for начинает анализировать парамет- ры с индекса 1. 222 Решения Упражнение 158. Удаляем комментарии ## # Удаляем все комментарии из файла Python (за исключением ситуаций, когда # символ комментария указан в середине строки) # # Запрашиваем у пользователя имя исходного файла и открываем его try: in_name = input("Введите имя файла Python: ") inf = open(in_name, "r") except: # Выводим сообщение и завершаем работу программы в случае возникновения ошибки print("При открытии файла возникла проблема.") print("Завершение работы программы...") quit() # Запрашиваем у пользователя имя итогового файла и открываем его try: out_name = input("Введите имя нового файла: ") outf = open(out_name, "w") except: # Закрываем исходный файл, показываем сообщение об ошибке и завершаем программу inf.close() print("С создаваемым файлом возникла проблема.") print("Завершение работы программы...") quit() try: # Читаем строки из исходного файла, избавляем их от комментариев и # сохраняем в новом файле for line in inf: # Находим позицию символа комментария (–1, если его нет) pos = line.find("#") # Если комментарий есть, создаем # строковый срез со всеми знаками до него # и сохраняем обратно в переменную line if pos > –1: line = line[0 : pos] line = line + "\n" # Записываем потенциально измененную # строку в новый файл outf.write(line) # Закрываем файлы inf.close() outf.close() Позиция символа коммента- рия сохраняется в перемен- ной pos. Так что выражение line[0 : pos] указывает на все символы в строке до знака комментария, не включая его. Файлы и исключения 223 except: # Выводим сообщение об ошибке, если что–то пошло не так print("При обработке файла возникла проблема.") print("Завершаем программу...") Упражнение 159. Случайный пароль из двух слов ## # Генерируем пароль путем сцепления двух случайных слов. Длина пароля должна составлять # от 8 до 10 символов, а каждое слово должно быть длиной минимум 3 символа # from random import randrange WORD_FILE = "../Data/words.txt" Пароль, который мы создаем, должен содержать от 8 до 10 символов. Поскольку минимальная длина слова составляет 3 символа, а в пароле должно быть два слова, получается, что в пароле не может присутствовать слово длиной более 7 символов. # Читаем все слова из файла, оставляя только те из них, длина которых варьируется # от 3 до 7 символов, и сохраняем их в список words = [] inf = open(WORD_FILE, "r") for line in inf: # Удаляем символ новой строки line = line.rstrip() # Оставляем слова длиной от 3 до 7 символов if len(line) >= 3 and len(line) <= 7: words.append(line) # Закрываем файл inf.close() # Случайным образом выбираем первое слово для пароля first = words[randrange(0, len(words))] first = first.capitalize() # Выбираем второе слово для пароля до тех пор, пока оно не будет подходить по размеру password = first while len(password) < 8 or len(password) > 10: second = words[randrange(0, len(words))] second = second.capitalize() password = first + second # Отображаем случайный пароль print("Случайный пароль:", password) 224 Решения Упражнение 162. Книги без буквы E ## # Выводим процент слов, использующих все буквы в алфавите # Также найдем букву, реже остальных встречающуюся в словах # WORD_FILE = "../Data/words.txt" # Создадим словарь со счетчиком слов, содержащих каждую букву. # Для каждой буквы инициализируем счетчик нулем counts = {} for ch in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": counts[ch] = 0 # Открываем файл, обрабатываем каждое слово и обновляем словарь со счетчиками num_words = 0 inf = open(WORD_FILE, "r") for word in inf: # Переводим слово в верхний регистр и избавляемся от символа новой строки word = word.upper().rstrip() # Перед обновлением словаря нужно создать список уникальных букв в слове. # Иначе мы будем увеличивать счетчик для повторяющихся букв в слове. # Также будем игнорировать небуквенные символы unique = [] for ch in word: if ch not in unique and ch >= "A" and ch <= "Z": unique.append(ch) # Увеличим счетчики для всех букв в списке уникальных символов for ch in unique: counts[ch] = counts[ch] + 1 # Увеличиваем количество обработанных слов num_words = num_words + 1 # Закрываем файл inf.close() # Выводим результат для каждой буквы. Параллельно определяем, какая буква # встречается в словах наиболее редко, чтобы вывести ее отдельно. smallest_count = min(counts.values()) for ch in sorted(counts): if counts[ch] == smallest_count: smallest_letter = ch percentage = counts[ch] / num_words * 100 print(ch, "встречается в %.2f процентах слов" % percentage) # Отображаем самую редко используемую букву в словах print() print("Буква, от которой легче всего будет избавиться:", smallest_letter) Файлы и исключения 225 Упражнение 163. Популярные детские имена ## # Отображаем мужские и женские имена, бывшие самыми популярными как минимум # в одном году с 1900–го по 2012–й # FIRST_YEAR = 1900 LAST_YEAR = 2012 ## Загружаем первую строку из файла, извлекаем имя и добавляем его к списку имен, # если его там еще нет # @param fname – имя файла, из которого будут считываться данные # @param names – список, к которому будем добавлять данные (если они отсутствуют) # @return (None) def LoadAndAdd(fname, names): # Открываем файл, читаем первую строку и извлекаем имя inf = open(fname, "r") line = inf.readline() inf.close() parts = line.split() name = parts[0] # Добавляем имя в список, если оно там еще не присутствует if name not in names: names.append(name) # Отображаем мужские и женские имена, бывшие самыми популярными как минимум # в одном году с 1900–го по 2012–й def main(): # Создаем списки для хранения самых популярных имен girls = [] boys = [] # Обрабатываем все годы из диапазона, читая первые строки из файлов с мужскими и женскими именами for year in range(FIRST_YEAR, LAST_YEAR + 1): girl_fname = "../Data/BabyNames/" + str(year) + \ "_GirlsNames.txt" boy_fname = "../Data/BabyNames/" + str(year) + \ "_BoysNames.txt" В данном решении я предположил, что файл с именами лежит не в той же папке, где файл Python. Если ваши файлы находятся в той же директории, часть пути к файлу ../Data/BabyNames/ нужно пропустить. LoadAndAdd(girl_fname, girls) 226 Решения LoadAndAdd(boy_fname, boys) # Выводим списки print("Самые популярные имена девочек:") for name in girls: print(" ", name) print() print("Самые популярные имена мальчиков: ") for name in boys: print(" ", name) # Вызов основной функции main() Упражнение 167. Проверяем правильность написания ## # Находим и отображаем все слова в файле, написанные неправильно # from only_words import onlyTheWords import sys WORDS_FILE = "../Data/words.txt" # Убедимся, что программе передано допустимое количество аргументов командной строки if len(sys.argv) != 2: print("При вызове программы должен быть указан один аргумент.") print("Завершаем программу...") quit() # Открываем файл. Выходим, если возникла ошибка try: inf = open(sys.argv[1], "r") except: print("Ошибка при открытии файла '%s' на чтение. Завершаем программу..." % \ sys.argv[1]) quit() # Загружаем все слова в словарь. В значения ставим 0, но использовать его не будем valid = {} words_file = open(WORDS_FILE, "r") for word in words_file: # Переводим слово в нижний регистр и удаляем символ новой строки word = word.lower().rstrip() # Добавляем слово в словарь valid[word] = 0 words_file.close() Файлы и исключения 227 В данном решении используются словари со словами в виде ключей и неисполь- зуемыми значениями. В целом эффективнее в этой ситуации будет использовать наборы (set), если вы знакомы с подобной структурой данных. Списки использовать не рекомендуется из-за их медлительности при поиске элементов. # Читаем все строки из файла, добавляя слова с ошибками в соответствующий список misspelled = [] for line in inf: # Избавляемся от знаков препинания при помощи функции из упражнения 117 words = onlyTheWords(line) for word in words: # Если слово написано неправильно и отсутствует в списке, добавляем его туда if word.lower() not in valid and word not in misspelled: misspelled.append(word) # Закрываем анализируемый файл inf.close() # Отображаем слова с ошибками или сообщение об их отсутствии if len(misspelled) == 0: print("Все слова написаны правильно.") else: print("Следующие слова написаны неправильно:") for word in misspelled: print(" ", word) Упражнение 169. Редактирование текста в файле ## # Редактируем файл, удаляя в нем служебные слова. Отредактированная версия # записывается в новый файл # # Заметьте, что в этой программе не выполняются проверки на ошибки # и она регистрозависимая # # Запрашиваем у пользователя имя файла для редактирования и открываем его inf_name = input("Введите имя файла для редактирования: ") inf = open(inf_name, "r") # Запрашиваем у пользователя имя файла со служебными словами и открываем его sen_name = input("Введите имя файла со служебными словами: ") sen = open(sen_name, "r") # Загружаем все служебные слова в список words = [] line = sen.readline() 228 Решения while line != "": line = line.rstrip() words.append(line) line = sen.readline() # Закрываем файл со служебными словами sen.close() Файл со служебными словами может быть закрыт в середине программы, поскольку все слова из него уже считаны в список. # Запрашиваем у пользователя имя нового файла и открываем его outf_name = input("Введите имя нового файла: ") outf = open(outf_name, "w") # Считываем все строки из исходного файла. Заменяем все служебные слова на звездочки. # Пишем строки в новый файл. line = inf.readline() while line != "": # Ищем и заменяем служебные слова. Количество звездочек соответствует # длине исходного слова for word in words: line = line.replace(word, "*" * len(word)) # Пишем измененную строку в новый файл outf.write(line) # Читаем следующую строку из исходного файла line = inf.readline() # Закрываем исходный и новый файлы inf.close() outf.close() Упражнение 170. Пропущенные комментарии ## # Находим и отображаем имена функций Python, которым не предшествует строка с комментарием # from sys import argv # Проверяем аргументы командной строки if len(argv) == 1: print("По крайней мере одно имя файла должно присутствовать в качестве", \ "аргумента командной строки.") print("Завершаем программу...") Файлы и исключения 229 quit() # Обрабатываем все файлы, имена которых переданы в виде аргументов командной строки for fname in argv[1 : len(argv)]: # Попытка обработать файл try: inf = open(fname, "r") # Двигаясь по файлу, нам важно хранить копию предыдущей строки, чтобы # можно было проверить, начинается ли она с символа комментария. # Также нам необходимо считать строки в файле prev = " " lnum = 1 Переменная prev должна быть инициализирована строкой длиной как минимум в один символ. Иначе программа закроется аварийно, если в первой строке анали- зируемого файла будет начинаться определение функции. # Считываем все строки из файла for line in inf: # Если нашли функцию без комментария if line.startswith("def ") and prev[0] != "#": # Ищем первую открывающую скобку в строке, чтобы считать имя функции bracket_pos = line.index("(") name = line[4 : bracket_pos] # Отображаем информацию о недокументированной функции print("%s строка %d: %s" % (fname, lnum, name)) # Сохраняем текущую строку и обновляем счетчик prev = line lnum = lnum + 1 # Закрываем текущий файл inf.close() except: print("Возникла проблема с файлом '%s'." % fname) print("Идем к следующему файлу...") Глава 16 Рекурсия Упражнение 173. Сумма значений ## # Вычисление суммы значений, введенных пользователем. Для окончания ввода # необходимо оставить ввод пустым # ## Вычисление суммы значений, введенных пользователем # @return сумма введенных значений def readAndTotal(): # Запрашиваем значение у пользователя line = input("Введите число (пропустите ввод для завершения): ") # Базовый случай: пользователь пропустил ввод, возвращаем 0 if line == "": return 0 else: # Рекурсивный случай: преобразуем line в число и используем рекурсию для # чтения следующих строк return float(line) + readAndTotal() # Запрашиваем у пользователя ряд чисел и отображаем их сумму def main(): total = readAndTotal() print("Сумма введенных чисел:", total) # Вызов основной функции main() Упражнение 178. Рекурсивные палиндромы ## # Определяем, является ли введенная строка палиндромом, с использованием рекурсии # ## Определяем, является ли введенная строка палиндромом Рекурсия 231 # @param s – строка для проверки # @return True, если палиндром, False в противном случае def isPalindrome(s): # Базовый случай: пустая строка является палиндромом, так же, как и строка длиной в один символ if len(s) <= 1: return True # Рекурсивный случай: строку можно считать палиндромом, если первый и последний # символы одинаковые, а подстрока, исключающая эти символы, также является палиндромом return s[0] == s[len(s) – 1] and \ isPalindrome(s[1 : len(s) – 1]) # Определяем, является ли введенная строка палиндромом def main(): # Запрашиваем строку у пользователя line = input("Введите строку: ") # Проверяем и выводим результат if isPalindrome(line): print("Это палиндром!") else: print("Это не палиндром.") # Вызов основной функции main() Упражнение 180. Редакционное расстояние ## # Вычисляем и отображаем редакционное расстояние между строками # ## Вычисляем и отображаем редакционное расстояние между строками # @param s – первая строка # @param t – вторая строка # @return редакционное расстояние между этими строками def editDistance(s, t): # Если одна из строк пустая, то в редакционное расстояние включается по одному пункту # для вставки каждого символа из второй строки if len(s) == 0: return len(t) elif len(t) == 0: return len(s) else: cost = 0 # Если последние символы не совпадают, устанавливаем cost в 1 |