Математический анализ. 3е издание
Скачать 4.86 Mb.
|
lines = [line.rstrip() for line in open('script1.py')] >>> lines ['import sys', 'print sys.path', 'x = 2', 'print 2 ** 33'] Это выражение значительную часть работы выполняет неявно – ин терпретатор сканирует файл и автоматически собирает список резуль татов выполнения операции. Кроме того, это наиболее эффективный способ, потому что большая часть действий выполняется внутри ин терпретатора Python, который работает наверняка быстрее, чем экви валентная инструкция for. Напомню еще раз, что при работе с боль шими файлами выигрыш в скорости от применения генераторов спи сков может оказаться весьма существенным. Синтаксис расширенного генератора списков В действительности генераторы списков могут иметь еще более слож ный вид. Например, в цикл for, вложенный в выражение, можно доба вить оператор if для отбора результатов, для которых условное выра жение дает истинное значение. Например, предположим, что нам требуется повторить предыдущий пример, но при этом необходимо отобрать только строки, начинаю щиеся с символа p (возможно, первый символ в каждой строке – код действия некоторого вида). Достичь поставленной цели можно, если добавить фильтрующий оператор if: >>> lines = [line.rstrip() for line in open('script1.py') if line[0] == 'p'] >>> lines ['print sys.path', 'print 2 ** 33'] В этом примере оператор if проверяет, является ли первый символ в строке символом p. Если это не так, строка не включается в список результатов. Это достаточно длинное выражение, но его легко понять, если преобразовать в эквивалентный простой цикл for (вообще любой генератор списков можно перевести в эквивалентную реализацию на базе инструкции for, добавляя отступы к каждой последующей части): >>> res = [] >>> for line in open('script1.py'): ... if line[0] == 'p': ... res.append(line.rstrip()) >>> res ['print sys.path', 'print 2 ** 33'] Эта инструкция for выполняет эквивалентные действия, но занимает четыре строки вместо одной и работает существенно медленнее. В заключение 361 В случае необходимости генераторы списков могут иметь еще более сложный вид. Например, они могут содержать вложенные циклы, оформленные в виде серии операторов for. На самом деле полный син таксис допускает указывать любое число операторов for, каждый из которых может иметь ассоциированный с ним оператор if (подробнее о синтаксисе генераторов выражений рассказывается в главе 17). Например, следующий фрагмент создает список результатов операции конкатенации x+y для всех x в одной строке и для всех y – в другой. В результате получаются сочетания символов в двух строках: >>> [x + y for x in 'abc' for y in 'lmn'] ['al', 'am', 'an', 'bl', 'bm', 'bn', 'cl', 'cm', 'cn'] Чтобы проще было понять это выражение, его также можно преобра зовать в форму инструкции, добавляя отступы к каждой последующей части. Следующий фрагмент представляет собой эквивалентную, но более медленную реализацию: >>> res = [] >>> for x in 'abc': ... for y in 'lmn': ... res.append(x + y) >>> res ['al', 'am', 'an', 'bl', 'bm', 'bn', 'cl', 'cm', 'cn'] Даже с повышением уровня сложности выражения генераторов спи сков могут иметь очень компактный вид. Вообще они предназначены для реализации простых итераций – для реализации сложных дейст вий более простая инструкция for наверняка будет проще и для пони мания, и для изменения в будущем. Обычно, если чтото в программи ровании для вас оказывается слишком сложным, возможно это не са мое лучшее решение. Мы еще вернемся к итераторам и генераторам списков в главе 17, где будем рассматривать их в контексте функций, где вы увидите, что они связаны с функциями не менее тесно, чем с инструкциями циклов. В заключение В этой главе мы исследовали инструкции циклов языка Python, а так же некоторые концепции, имеющие отношение к циклам. Мы рас смотрели инструкции while и for во всех подробностях и узнали о свя занных с ними блоках else. Мы также изучили инструкции break и continue, которые могут использоваться только внутри циклов. Дополнительно мы познакомились с итерационным протоколом в язы ке Python, обеспечивающим возможность выполнять итерации по объ ектам, не являющимся последовательностями, и с генераторами спи сков. Как было показано, генераторы списков, применяющие заданные 362 Глава 13. Циклы while и for выражения ко всем элементам любого итерируемого объекта, напоми нают циклы for. Эта глава завершает наш обзор процедурных инструкций. Следующая глава, завершающая эту часть книги, обсуждает возможности доку ментирования программного кода на языке Python. Документация также является частью синтаксической модели, и кроме того, она яв ляется важным компонентом хорошо написанных программ. В сле дующей главе мы также рассмотрим ряд упражнений к этой части книги, прежде чем перенесем свое внимание к более крупным структу рам, таким как функции. Однако, как обычно, прежде чем двинуться дальше, попробуйте ответить на контрольные вопросы. Закрепление пройденного Контрольные вопросы 1. Когда выполняется блок else в циклах? 2. Как в языке Python можно запрограммировать счетный цикл? 3. Как взаимосвязаны циклы for и итераторы? 4. Как взаимосвязаны циклы for и генераторы списков? 5. Назовите четыре разных контекста итераций в языке Python. 6. Какой способ построчного чтения содержимого файлов считается наиболее оптимальным? 7. Какое оружие вы ожидали бы увидеть в руках испанской инквизи ции? Ответы 1. Блок else в циклах while или for выполняется один раз после выхо да из цикла при условии, что цикл завершается обычным образом (без использования инструкции break). Инструкция break осуществ ляет немедленный выход из цикла и пропускает блок else (если та ковой присутствует). 2. Счетные циклы могут быть реализованы на базе инструкции while при условии, что вычисление индексов будет производиться вруч ную, или на базе инструкции for, которая использует встроенную функцию range для генерирования последовательности целых чи сел. Ни один из этих способов не является предпочтительным в язы ке Python; если вам необходимо просто обойти все элементы в по следовательности, везде, где только возможно, используйте про стой цикл for, без функции range или счетчиков. Такая реализация и выглядит проще, и обычно работает быстрее. 3. Цикл for использует итерационный протокол для обхода элементов объекта. На каждой итерации он вызывает метод next объекта и пе Закрепление пройденного 363 рехватывает исключение StopIteration, по которому определяет мо мент окончания итераций. 4. Оба они являются инструментами итераций. Генераторы списков представляют простой и эффективный способ выполнения задачи, типичной для циклов for: сбор результатов применения выражения ко всем элементам итерируемого объекта. Генераторы списков всегда можно преобразовать в цикл for, а кроме того, генераторы списков по своему внешнему виду напоминают заголовок инструкции for. 5. В число итерационных контекстов языка Python входят: цикл for, генераторы списков, встроенная функция map, оператор in проверки вхождения, а также встроенные функции sorted, sum, any и all. В эту категорию также входят встроенные функции list и tuple, строко вый метод join и операции присваивания последовательностей – все они следуют итерационному протоколу (метод next) для обхода ите рируемых объектов. 6. Рекомендуемый в настоящее время способ чтения строк из тексто вого файла – не читать файл явно вообще. Вместо этого предлагает ся открыть файл в итерационном контексте, например в цикле for или в генераторе списков, и позволить итерационному инструменту на каждой итерации автоматически извлекать по одной строке из файла с помощью метода next. Такой подход считается более опти мальным в смысле простоты программирования, скорости выпол нения и использования памяти. 7. Любой из следующих вариантов я приму как правильный ответ: устрашение, шантаж, хорошие красные униформы, удобная ку шетка и мягкие подушки. 14 Документация Эта глава завершает третью часть книги изучением приемов и инстру ментов, используемых для документирования программного кода на языке Python. Несмотря на то, что программный код Python изначаль но обладает высокой удобочитаемостью, некоторый объем уместно расположенных, внятных комментариев может существенно облег чить другим людям понимание принципа действия ваших программ. Язык Python включает синтаксические конструкции и инструменты, облегчающие документирование программ. Эта тема в большей степени связана с инструментальными средствами и, тем не менее, она рассматривается здесь, отчасти потому что она имеет некоторое отношение к синтаксической модели языка Python, а отчасти как источник сведений для тех, кто изо всех сил пытается понять возможности языка Python. Преследуя эту последнюю цель, я дополню указания о документировании, которые были даны в главе 4. Как обычно, эта глава завершается предупреждениями о наиболее час то встречающихся ловушках, контрольными вопросами к главе и уп ражнениями к этой части книги. Источники документации в языке Python К настоящему моменту вы уже наверняка начинаете понимать, что Python изначально включает в себя удивительно широкие функцио нальные возможности – встроенные функции и исключения, предо пределенные атрибуты и методы объектов, модули стандартной биб лиотеки и многое другое. Более того, на самом деле мы лишь слегка коснулись каждой из этих категорий. Один из первых вопросов, который часто задают удивленные новички: «Как мне найти информацию обо всех встроенных возможностях?». Источники документации в языке Python 365 Этот раздел рассказывает о различных источниках документации, доступных в языке Python. Здесь также будут представлены строки документирования (docstrings) и система PyDoc, которая использует их. Эти темы мало связаны с самим языком программирования, но они будут иметь большое значение, как только вы подойдете к приме рам и упражнениям в этой части книги. Как показано в табл. 14.1, существует множество мест, где можно оты скать информацию о Python, и объем этой информации все увеличива ется. Поскольку документация играет важную роль в практическом программировании, мы исследуем каждую из этих категорий в сле дующих разделах. Таблица 14.1. Источники документации в языке Python Комментарии # Комментарии, начинающиеся с символа решетки, представляют собой самый элементарный способ документирования программного кода. Интерпретатор просто игнорирует весь текст, который следует за сим волом # (при условии, что он находится не внутри строкового литера ла), поэтому вы можете помещать вслед за этими символами слова и описания, предназначенные для программистов. Впрочем, такие ком ментарии доступны только в файлах с исходными текстами – для за писи комментариев, которые будут доступны более широко, следует использовать строки документирования. В настоящее время считается, что строки документирования лучше подходят для создания функционального описания (например, «мой файл делает тото и тото»), а комментарии, начинающиеся с символа #, лучше подходят для описания некоторых особенностей программ ного кода (например, «это странное выражение делает тото и тото»). О строках документирования мы поговорим чуть ниже. Форма Назначение Комментарии # Документация внутри файла Функция dir Получение списка атрибутов объектов Строки документирования: __doc__ Документация внутри файла, присоединяе мая к объектам PyDoc: функция help Интерактивная справка по объектам PyDoc: отчеты в формате HTML Документация к модулям для просмотра в броузере Стандартный набор руководств Официальное описание языка и библиотеки Вебресурсы Интерактивные учебные руководства, при меры и т. д. Печатные издания Руководства, распространяемые на коммер ческой основе 366 Глава 14. Документация Функция dir Функция dir – это простой способ получить список всех атрибутов объ екта (т. е. методов и элементов данных). Она может быть вызвана для любого объекта, который имеет атрибуты. Например, чтобы узнать, что имеется в стандартном библиотечном модуле sys, просто импорти руйте его и передайте имя модуля функции dir: >>> import sys >>> dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', '__stdin__', '__stdout__', '_getframe', 'argv', 'builtin_module_names', 'byteorder', 'copyright', 'displayhook', 'dllhandle', 'exc_info', 'exc_type', 'excepthook', ...остальные имена опущены...] Здесь показаны только некоторые из имен; чтобы получить полный список, выполните эти инструкции на своей машине. Чтобы узнать, какие атрибуты содержат объекты встроенных типов, передайте функции dir литерал требуемого типа. Например, чтобы увидеть атрибуты списков и строк, можно передать функции пустой объект: >>> dir([]) ['__add__', '__class__', ...остальные имена опущены... 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] >>> dir('') ['__add__', '__class__', ...остальные имена опущены... 'capitalize', 'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', ...остальные имена опущены...] Результаты работы функции dir для любого встроенного типа включа ют набор атрибутов, которые имеют отношение к реализации этого ти па (методы перегруженных операторов); все они начинаются и закан чиваются двумя символами подчеркивания, чтобы сделать их отлич ными от обычных имен, и вы можете пока просто игнорировать их. Того же эффекта можно добиться, передав функции dir имя типа вме сто литерала: >>> dir(str) == dir('') # Результат тот же, что и в предыдущем примере True >>> dir(list) == dir([]) True Такой прием работает по той простой причине, что имена функций преобразования, такие как str и list, в языке Python фактически яв ляются именами типов – вызов любого из этих конструкторов приво дит к созданию экземпляра этого типа. Подробнее о конструкторах Источники документации в языке Python 367 и о перегрузке операторов мы будем говорить в шестой части книги, когда будем обсуждать классы. Функция dir служит своего рода «кратким напоминанием» – она пре доставляет список имен атрибутов, но ничего не сообщает о том, что эти имена означают. За этой информацией необходимо обращаться к следующему источнику документации. Строки документирования: __doc__ Помимо комментариев, начинающихся с символа #, язык Python под держивает возможность создания документации, которая автоматиче ски присоединяется к объектам и доступна во время выполнения. Син таксически такие строки располагаются в начале файлов модулей, функций и классов, перед исполняемым программным кодом (перед ними вполне могут располагаться комментарии #). Интерпретатор ав томатически помещает строки документирования в атрибут __doc__ со ответствующего объекта. Строки документирования, определяемые пользователем В качестве примера рассмотрим файл docstrings.py. Строки докумен тирования в нем располагаются в самом его начале, а также в начале функции и класса. Здесь для создания многострочных описаний фай ла и функции я использовал строки в тройных кавычках, но допуска ется использовать строки любого типа. Мы еще не познакомились с инструкциями def и class, поэтому вы можете просто игнорировать все, что находится после них, за исключением строк в самом начале: """ Module documentation Words Go Here """ spam = 40 def square(x): """ function documentation can we have your liver then? """ return x **2 class employee: "class documentation" pass print square(4) print square.__doc__ Самое важное в протоколе документирования заключается в том, что ваши комментарии становятся доступны для просмотра в виде атрибу тов __doc__ после того, как файл будет импортирован. Поэтому, чтобы отобразить строки документирования, связанные с модулем и его объ 368 Глава 14. Документация ектами, достаточно просто импортировать файл и вывести значения их атрибутов __doc__, где интерпретатор сохраняет текст: >>> import docstrings 16 function documentation can we have your liver then? >>> print docstrings.__doc__ Module documentation Words Go Here >>> print docstrings.square.__doc__ function documentation can we have your liver then? >>> print docstrings.employee.__doc__ class documentation Обратите внимание, что для вывода строк документирования необходи мо явно использовать инструкцию print, в противном случае будет выво диться единственная строка со встроенными символами новой строки. Кроме того, существует возможность присоединять строки документи рования к методам классов (эта возможность описывается ниже), но так как они представлены инструкциями def, вложенными в классы, это не является особым случаем. Чтобы извлечь строку с описанием метода класса, определяемого внутри модуля, необходимо указать имя модуля, класса и метода: module.class.method.__doc__ (примеры строк документирования методов приводятся в главе 26). Стандарты оформления строк документирования Не существует какогото общепринятого стандарта, который регламен тировал бы, что должно входить в строки документирования (хотя в не которых компаниях существуют свои внутренние стандарты). В свое время предлагались различные шаблоны и языки разметки (например, HTML или XML), но они не завоевали популярность в мире Python. И, положа руку на сердце, едва ли мы дождемся появления программи стов, которые захотят писать документацию на языке разметки HTML! Вообще, среди программистов документация обычно отходит на зад ний план. Если вы увидите хоть какието комментарии в файле, счи тайте, что вам повезло. Однако я настоятельно рекомендую тщательно документировать свой программный код – это действительно очень важная часть хорошо написанного программного кода. Замечу, что нет никаких стандартов на структуру строк документирования, поэто му, если вы хотите использовать их, чувствуйте себя свободными. |