Программирование на Python 3. Руководство издательство СимволПлюс
Скачать 3.74 Mb.
|
Пример: make_html_skeleton.py 221 not in {"y", "yes"}): break Функция datetime.date.today() возвращает объект datetime.date, кото рый хранит текущую дату. Нам требуется лишь значение атрибута year этого объекта. Во все остальные элементы данных записывается значение None, так как для них не существует разумных значений по умолчанию. В цикле while программа выводит заголовок и вызывает функцию populate_information() , передавая ей словарь information. Внутри функ ции populate_information() производится заполнение этого словаря. За тем вызывается функция make_html_skeleton(), она принимает большое число аргументов, но чтобы явно не указывать значение каждого из них, мы просто распаковываем словарь information. Если пользователь прерывает процесс создания заготовки страницы, например, отказом от ввода обязательного значения, программа выво дит сообщение «Cancelled» (отменено). В конце каждой итерации (не зависимо от того, было ли отменено создание заготовки страницы или нет) пользователю задается вопрос: не желает ли он создать еще одну заготовку. Если пользователь отвечает отказом, производится выход из цикла и программа завершает работу. def populate_information(information): name = get_string("Enter your name (for copyright)", "name", information["name"]) if not name: raise CancelledError() year = get_integer("Enter copyright year", "year", information["year"], 2000, datetime.date.today().year + 1, True) if year == 0: raise CancelledError() filename = get_string("Enter filename", "filename") if not filename: raise CancelledError() if not filename.endswith((".htm", ".html")): filename += ".html" information.update (name=name, year=year, filename=filename, title=title, description=description, keywords=keywords, stylesheet=stylesheet) Мы опустили программный код, который запрашивает заголовок и текст описания, ключевые слова HTML и имя файла с таблицами сти лей. Во всех этих случаях используется функция get_string(), которую мы увидим очень скоро. Достаточно лишь отметить, что эта функция принимает текст вопроса, «имя» соответствующей переменной (для вывода в сообщении об ошибке) и необязательное значение по умолча нию. Точно так же функция get_integer() принимает текст вопроса, 222 Глава 4. Управляющие структуры и функции имя переменной, значение по умолчанию, минимальное и максималь ное значения, а также признак – допустимо ли значение 0. В конце функция заполняет словарь information новыми значениями, используя именованные аргументы. В каждой паре key=value имя key соответствует имени ключа в словаре, значение которого замещается указанным значением value, и в данном случае каждое значение value является переменной с тем же именем, что и соответствующий ей ключ словаря. Эта функция не имеет явного возвращаемого значения (поэтому она возвращает значение None). Она может также завершаться в случае по явления исключения CancelledError, в этом случае исключение будет передано вверх по стеку вызовов и обработано в функции main(). Функцию make_html_skeleton() мы рассмотрим в два этапа. def make_html_skeleton(year, name, title, description, keywords, stylesheet, filename): copyright = COPYRIGHT_TEMPLATE.format(year, xml.sax.saxutils.escape(name)) title = xml.sax.saxutils.escape(title) description = xml.sax.saxutils.escape(description) keywords = ",".join([xml.sax.saxutils.escape(k) for k in keywords]) if keywords else "" stylesheet = (STYLESHEET_TEMPLATE.format(stylesheet) if stylesheet else "") html = HTML_TEMPLATE.format(title=title, copyright=copyright, description=description, keywords=keywords, stylesheet=stylesheet) Чтобы получить текст с указанием авторских прав, мы вызываем ме тод str.format() для строки COPYRIGHT_TEMPLATE, передавая год и имя (до полнительно выполняя экранирование служебных символов HTML) в виде позиционных аргументов для замены полей {0} и {1}. В тексте за головка и описания мы просто экранируем служебные символы HTML. В случае ключевых слов у нас может быть два варианта действий, ко торые реализуются с использованием условного выражения. Если ключевые слова не были введены, то в качестве значения переменной keywords будет использоваться пустая строка. В противном случае с по мощью генератора списков выполняется обход всех ключевых слов и создается новый список строк, в каждой из которых выполняется эк ранирование служебных символов HTML. После этого, с помощью ме тода str.join(), мы объединяем элементы списка в единую строку, раз деляя их запятыми. Текст переменной stylesheet создается аналогичным способом, что и текст с указанием авторских прав, но с применением условного вы ражения, чтобы в случае отсутствия имен файлов таблиц стилей полу чалась пустая строка. Пример: make_html_skeleton.py 223 Текст для переменной html создается из шаблона HTML_ TEMPLATE , где для передачи данных в замещаемые поля используются не позиционные аргументы, как в других строках шаблонов, а именованные. fh = None try: fh = open(filename, "w", encoding="utf8") fh.write(html) except EnvironmentError as err: print("ERROR", err) else: print("Saved skeleton", filename) finally: if fh is not None: fh.close() Как только заготовка файла HTML будет готова, мы записываем ее в файл с заданным именем. После этого пользователь извещается, что файл заготовки был сохранен, или выводится сообщение об ошибке, если чтото пошло не так. Как обычно, чтобы гарантировать закрытие файла, если он был открыт, используется предложение finally. def get_string(message, name="string", default=None, minimum_length=0, maximum_length=80): message += ": " if default is None else " [{0}]: ".format(default) while True: try: line = input(message) if not line: if default is not None: return default if minimum_length == 0: return "" else: raise ValueError("{0} may not be empty".format( name)) if not (minimum_length <= len(line) <= maximum_length): raise ValueError("{0} must have at least {1} and " "at most {2} characters".format( name, minimum_length, maximum_length)) return line except ValueError as err: print("ERROR", err) Функция имеет один обязательный аргумент message и четыре необяза тельных аргумента. Если значение аргумента default определено, оно включается в строку message, чтобы пользователь мог видеть значение по умолчанию, которое будет использоваться, если он просто нажмет клавишу Enter, не вводя никакого текста. Остальная часть функции заключена в бесконечный цикл. Цикл может быть прерван вводом Метод str. format() , стр. 100 224 Глава 4. Управляющие структуры и функции допустимой строки или в результате простого нажатия клавиши Enter, когда используется значение по умолчанию (если определено). Кроме того, пользователь может прервать цикл и завершить работу программы, нажав комбинацию клавиш Ctrl+C, – в этом случае возбуж дается исключение KeyboardInterrupt, но так как это исключение не об рабатывается ни одним из обработчиков, имеющихся в программе, это приведет к завершению программы с выводом диагностической ин формации. Следовало ли оставлять такую возможность прерывать цикл? Если бы мы этого не сделали и в программе обнаружилась бы ошибка, мы не оставили бы пользователю никакой возможности пре рвать работу программы, кроме как уничтожить процесс. Если нет достаточно веских причин препятствовать завершению программы по нажатию комбинации Ctrl+C, не следует обрабатывать это исключение ни в одном из обработчиков. Примечательно, что эта функция достаточно универсальна и может использоваться не только в программе make_html_skeleton.py, но и во многих других интерактивных программах подобного типа. Такого многократного использования функции можно было бы добиться про стым копированием текста, но такой прием может стать источником головной боли для того, кто будет сопровождать программы. В следую щей главе мы узнаем, как создавать собственные модули, вмещающие функциональные возможности, которые могут совместно использо ваться большим числом программ. def get_integer(message, name="integer", default=None, minimum=0, maximum=100, allow_zero=True): Эта функция по своей структуре настолько близка к функции get_ string() , что нет необходимости воспроизводить ее здесь. (Безусловно, эта функция присутствует в исходных текстах примеров к книге.) Па раметр allow_zero может быть полезен, когда 0 не является допусти мым значением, но когда желательно обеспечить возможность ввода ошибочного значения, чтобы предоставить способ прервать процедуру создания заготовки. Другой способ, который можно было бы использо вать, заключается в том, чтобы определить недопустимое значение в качестве значения по умолчанию; тогда возврат такого значения оз начал бы, что пользователь отменил операцию. Последняя инструкция в программе – это простой вызов функции main() . Общий объем программы составляет чуть больше 150 строк, и она демонстрирует некоторые особенности языка Python, которые были представлены в этой и в предыдущих главах. В заключение 225 В заключение В этой главе мы рассмотрели полный синтаксис всех управляющих структур языка Python. Здесь также было показано, как возбуждать и обрабатывать исключения и как создавать свои типы исключений. Большая часть главы была посвящена созданию собственных функ ций. Мы увидели, как создаются функции, познакомились с некото рыми правилами выбора имен для функций и их параметров. Мы так же увидели, как можно добавлять описание функций. Подробно был рассмотрен универсальный синтаксис определения параметров и пере дачи аргументов в языке Python, включая возможность передачи фик сированного и переменного числа позиционных и именованных аргу ментов, а также возможность определения для аргументов значений по умолчанию – как неизменяемых, так и изменяемых типов. Кроме того, мы коротко повторили порядок использования оператора распа ковывания последовательностей * и показали, как выполнять распа ковывание отображений с помощью оператора **. Когда возникает необходимость присвоить глобальной переменной но вое значение внутри функции, она должна быть объявлена с помощью инструкции global, чтобы предотвратить создание оператором при сваивания новой локальной переменной. Однако вообще глобальные переменные лучше использовать только в качестве констант. Лямбдафункции часто используются в качестве значения аргументов других функций или в других случаях, где функция должна переда ваться в виде параметра. В этой главе было показано, что лямбда функции могут использоваться как для создания анонимных функ ций, так и для создания коротких именованных функций – путем при сваивания их переменным. В главе также было рассмотрено применение инструкции assert. Эта инструкция очень удобна для проверки истинности предварительных условий и результатов при каждом обращении к функции и может оказать действенную помощь в создании надежных программ и в лик видации ошибок. В этой главе мы рассмотрели фундаментальные основы создания функций, а, кроме того, в нашем распоряжении имеется еще масса других приемов. Сюда входят возможность создания динамических функций (эти функции создаются во время выполнения программы, причем их реализация может изменяться в зависимости от обстоя тельств), рассматриваемых в главе 5; локальных (вложенных) функ ций, рассматриваемых в главе 7; а также рекурсивных функций, гене раторов функций и т. д., о чем будет рассказываться в главе 8. В языке Python имеется значительное число встроенных функций и обширнейшая стандартная библиотека, тем не менее все равно остает ся вероятность, что мы напишем такие функции, которые пригодятся 226 Глава 4. Управляющие структуры и функции во многих наших программах. Копирование функций из файла в файл может превратить в кошмар сопровождение таких программ, но, к счастью, Python предоставляет простое решение этой проблемы: мо дули. В следующей главе мы узнаем, как создавать свои собственные модули со своими функциями в них. Мы увидим, как выполнять им портирование функциональных возможностей из стандартной библио теки и из наших модулей, а также коротко рассмотрим, что может предложить стандартная библиотека, чтобы нам не пришлось повтор но изобретать колесо. Упражнения Напишите интерактивную программу обслуживания списков строк в файлах. При запуске программа должна создать список всех файлов с расшире нием .lst в текущем каталоге. Воспользуйтесь функцией os.listdir("."), чтобы получить список всех файлов, и отфильтруйте из него те файлы, которые не имеют расширения .lst. В случае отсутствия таких файлов программа должна попросить пользователя ввести имя файла и доба вить расширение .lst, если пользователь не сделал этого. Если были найдены один или более файлов .lst, программа должна вывести их имена в виде списка пронумерованных строк, начиная с 1. Пользова телю должно быть предложено ввести номер желаемого файла или 0; в последнем случае программа должна попросить у пользователя ввести имя нового файла. Если был указан существующий файл, программа должна прочитать его содержимое. Если файл пуст или было указано имя нового файла, программа должна вывести сообщение «no items are in the list» (спи сок не содержит элементов). В случае отсутствия элементов должно быть предложено два варианта действий: «Add» (добавить) и «Quit» (выйти). Если список содержит один или более элементов, строки из списка должны выводиться про нумерованными, начиная с 1, а из доступных действий должны быть предложены варианты «Add» (добавить), «Delete» (удалить), «Save» (сохранить) (если файл еще не сохранялся) и «Quit» (выйти). Если пользователь выбирает действие «Quit» и при этом имеются несохра ненные изменения, ему должна быть предоставлена возможность со хранить их. Ниже приводится пример сеанса работы с программой (большая часть пустых строк, а также заголовок «List Keeper», кото рый выводится всякий раз при выводе списка, были удалены из лис тинга): Choose filename: movies no items are in the list [A]dd [Q]uit [a]: a Add item: Love Actually Упражнения 227 1: Love Actually [A]dd [D]elete [S]ave [Q]uit [a]: a Add item: About a Boy 1: About a Boy 2: Love Actually [A]dd [D]elete [S]ave [Q]uit [a]: Add item: Alien 1: About a Boy 2: Alien 3: Love Actually [A]dd [D]elete [S]ave [Q]uit [a]: k ERROR: invalid choiceenter one of 'AaDdSsQq' Press Enter to continue... [A]dd [D]elete [S]ave [Q]uit [a]: d Delete item number (or 0 to cancel): 2 1: About a Boy 2: Love Actually [A]dd [D]elete [S]ave [Q]uit [a]: s Saved 2 items to movies.lst Press Enter to continue... 1: About a Boy 2: Love Actually [A]dd [D]elete [Q]uit [a]: Add item: Four Weddings and a Funeral 1: About a Boy 2: Four Weddings and a Funeral 3: Love Actually [A]dd [D]elete [S]ave [Q]uit [a]: q Save unsaved changes (y/n) [y]: Saved 3 items to movies.lst Функция main() должна быть не очень большой (не более 30 строк) и должна содержать только основной цикл программы. Напишите функцию, которая будет получать имя нового или существующего файла (и в последнем случае загружать элементы списка), и функцию, которая будет выводить перечень доступных действий и принимать выбор пользователя. Напишите также функции, которые будут добав лять элемент, удалять элемент, выводить список (либо имен файлов, либо элементов списка строк), загружать список и сохранять список. Вставьте в свою программу копии функций get_string() и get_integer() из программы make_html_skeleton.py или напишите свои собственные версии. При выводе элементов списка строк или имен файлов ширина поля для вывода номеров строк должна быть равна 1, если список содержит менее десяти элементов, 2 – если в списке менее 100 элементов и 3 – в противном случае. 228 Глава 4. Управляющие структуры и функции Всегда выводите элементы списка в алфавитном порядке, без учета ре гистра символов, и следите за состоянием списка (за наличием несо храненных изменений). Действие «Save» должно предлагаться только при наличии несохраненных изменений, а перед выходом программа должна спрашивать у пользователя, не желает ли он сохранить изме нения, только если таковые имеются. Добавление и удаление элемен тов считаются действиями, которые изменяют список, а после выпол нения операции сохранения список снова должен считаться неизме ненным. Пример решения находится в файле Listkeeper.py и занимает менее 200 строк программного кода. 5 Модули Функции позволяют упаковывать фрагменты программного кода, что бы его можно было многократно использовать по всей программе, а модули обеспечивают средство объединения функций (и, как мы уви дим в следующей главе, наших собственных типов данных) в коллек ции, чтобы их можно было использовать в разных программах. В язы ке Python имеются также средства создания пакетов – наборов моду лей, объединенных, как правило, по функциональным признакам или вследствие зависимости друг от друга. В первом разделе этой главы описывается синтаксис операции импор тирования функциональных возможностей из модулей и пакетов, вхо дящих в состав стандартной библиотеки, или из наших собственных модулей и пакетов. Затем в этом же разделе будет показано, как созда вать собственные пакеты и модули. Будут продемонстрированы два примера собственных модулей. Из них первый пример является ввод ным, а во втором демонстрируется, как решаются многочисленные проблемы, возникающие на практике, такие как платформенная неза висимость и тестирование. Во втором разделе дается краткий обзор стандартной библиотеки языка Python. Очень важно знать, что мо жет предложить стандартная библиотека, потому что ис пользование предопределенных функциональных воз можностей существенно ускоряет программирование, позволяя не создавать все и вся с чистого листа. Кроме того, многие модули из стандартной библиотеки исполь зуются очень широко. Они тщательно протестированы и обладают высокой надежностью. Помимо краткого об зора будет приведено несколько небольших примеров, иллюстрирующих типичные случаи использования. До Врезка «Электрон ная докумен тация», стр. 203 |