Лутц М. - Изучаем Python (1077325), страница 119
Текст из файла (страница 119)
В ходе импортирования инструкции в файле выполняются от начала и до конца, поэтому необходимо быть внимательнее, когда используются модули, импортирующие друг друга (эта ситуация называется рекурсивным импортом). Поскольку не все инструкции в модуле могут быть выполнены к моменту запуска процедуры импортирования Например, модуль ге1оас(а(1.ру, в листинге ниже, содержит функцию ге1оаб а11, автоматически выполняющую перезагрузку модуля, каждого импортируемого им модуля, и т. д„до самого конца каждой цепочки импортирования. Она использует словарь, с помощью которого отыскивает уже загруженные модули, рекурсию — для обхода цепочек импорта и модуль сурез из стандартной библиотеки (был представлен в конце главы 9), в котором просто предопределены значения атрибута Суре для всех встроенных типов. Глава 21.
Дополнительные воэможности модулей другого модуля, некоторые из его имен могут оказаться еще не опреде- ленными. а Файл гесог1 ру Х = 1 гщрог! гесог2 У = 2 р Запустить гесиг2, если он еще не бил импортироеан О Файл гЕСпг2.ру ггош гесиг1 ньрогт х Ггощ гесог1 шрот! У а ОК "Х' уше имеет значение а Ошибка П' еще не существует »> !Фрог! гесог1 Тгасеваск (тппегщоа! !аз!): Е!!е '<а!Ото>", !!пе 1, !и о Е!!е "гесог1.ру", !тпе 2, тп о !шрот! гесог2 Ет1е 'гесог2.ру", !тле 2, тп и Ггощ гесог1 !Фрог! У 1щрогтЕггог, саппа! !шрот! паше У и Ошибка. ' У еще не существует При рекурсивном импорте модуля гесс г1 и модуля гесс г2 интерпретатор не будет повторно выполнять инструкции модуля гесог1 (в противном случае это могло бы привести к бесконечному циклу), но пространство имен модуля гесог1 еще не заполнено до конца к моменту, когда он импортируется модулем гесс г2.
Решение2 Не используйте инструкцию ггощ в операции рекурсивного импорта (в самом деле!). Интерпретатор не зациклится, если вы все-таки сделаете это, но ваша программа попадет в зависимость от порядка следования инструкций в модулях. Существует два способа решения этой проблемы: ° Обычно можно ликвидировать рекурсивный импорт, подобный приведенному, правильно проектируя модули: увеличить согласованность внутри модуля и уменьшить взаимозависимость между модулями — это самое первое, что стоит попробовать сделать. Если вы используете инструкцию !Фрог!, чтобы получить модуль целиком, это может иметь, а может не иметь большого значения — имена модуля не будут доступны, пока позже не будут использованы полные имена для получения их значений. Но если для получения определенных имен используется инструкция г тощ, имейте в виду, у вас будет доступ только к тем именам, которые уже были определены в этом модуле. Например, рассмотрим следующие модули, гесог1 и гесог2, Модуль гесс г1 создает имя Х и затем импортирует гесс г2 до того, как присвоит значение имени У.
В этом месте модуль гесс г2 может импортировать модуль гесог1 целиком с помощью инструкции (врос! (он уже существует во внутренней таблице модулей интерпретатора), но если используется инструкция ! тощ, ей будет доступно только имя Х, а имя У, которому будет присвоено значение только после инструкции 1щро г! в гесс г1, еще не существует, поэтому возникнет ошибка: В заключение ° Если от циклов не удается избавиться полностью, попробуйте отсрочить обращение к именам модуля, используя инструкции 1вро гг и полные имена (вместо инструкции Тгов), или поместите инструкции Тгов либо внутрь функций 1чтобы они не вызывались в программном коде верхнего уровня), либо ближе к концу файла, чтобы отложить их выполнение.
В заключение В этой главе был рассмотрен ряд дополнительных концепций, связанных с модулями. Мы изучили приемы сокрытия данных, включение новых особенностей языка из модуля Тошге, возможности использования переменной паве, синтаксис относительного импортирования в пакетах и многое другое. Мы также исследовали проблемы проектирования модулей и познакомились с типичными ошибками при работе с модулями, что позволит вам избежать их в своем программном коде. Со следующей главы мы приступим к изучению объектно-ориентированного инструмента языка РуС)зоп — класса. Большая часть сведений, рассмотренных в последних нескольких главах, применима и здесь— классы располагаются в модулях и также являются пространствами имен, но они добавляют еще один элемент в поиск атрибутов, который называется «поиск в цепочке наследования».
Поскольку это последняя глава в этой части книги, прежде чем углубиться в объектно-ориентированное программирование, обязательно выполните упражнения к этой части книги. Но перед этим попробуйте ответить на контрольные вопросы главы, чтобы освежить в памяти темы, рассматривавшиеся здесь. Закрепление пройденного Контрольные вопросы 1. Что важно знать о переменных в программном коде верхнего уровня модуля, имена которых начинаются с одного символа подчеркивания2 2. Что означает, когда переменная паве модуля имеет значение " ваза "2 3.
Вчем разница междуинструкциями Тгов вуркр 1врог1 арав и Тгов . зврог1 арав2 4. Если пользователь вводит имя модуля в ответ на запрос программы, как импортировать этот модуль2 5. Чем отличается изменение списка ауа, рагс от изменения значения переменной окружения РУТНОНРАТН2 6. Импорт будущих изменений в языке возможен с помощью модуля То1оге, а возможен ли импорт из прошлого2 556 Ответы Упражнения к пятой части Решения приводятся в разделе «Часть Ч, Модулич приложения А. 1.
2. 3. 4. б. 6. Глава 21, Дополнительные возможности модулей Переменные в программном коде верхнего уровня модуля, чьи имена начинаются с одного символа подчеркивания, не копируются при импортировании с помощью инструкции Ггоа *. Однако они доступны при использовании инструкции зврогт и обычной формы инструкции Г гол. Если переменная паве модуля содержит строку " эаш ", это означает, что файл выполняется как самостоятельный сценарий, а не был импортирован в качестве модуля другим файлом в программе. То есть файл используется как программа, а не как библиотека.
Инструкция г гав зурнц 1зрогт зрав выполняет импортирование в абсолютном режиме, используя путь поиска в зув. ратл. Инструкция Ггов . 1врог1 зраа, напротив, выполняет импорт в относительном режиме — поиск модуля враз осуществляется сначала в пакете, где находится инструкция, и только потом в вув, рата. Как правило, ввод пользователя поступает в сценарий в виде строки — чтобы импортировать модуль по имени, заданному в виде строки, можно собрать и выполнить инструкцию 1врогт с помощью инструкции ехес или передать строку с именем функции зарог1, Изменения в вуз.ра1Л воздействуют только на работающую программу и носят временный характер — изменения будут утеряны сразу же после завершения программы. Содержимое переменной окружения РУТНОНРАТН хранится в операционной системе — оно оказывает воздействие на все программы, выполняемые на этом компьютере, а изменения сохраняются после завершения программ.
Нет, мы не можем импортировать из прошлого. Мы можем установить (или упорно использовать) более старую версию языка, но, как правило, самая лучшая версия — это последняя версия Ру1Ьоп.' Основы импортирования. Напишите программу, которая подсчитывает количество строк и символов в файле (в духе утилиты гос в операционной системы 'Уг(1Х). В своем текстовом редакторе создайте модуль с именем тутаев.ру, который экспортирует три имени: ° Функцию сооп11з пав(паве), которая читает входной файл и подсчитывает число строк в нем (подсказка: большую часть работы можно выполнить с помощью метода Гз1е, геа01зпев, а оставшуюся часть — с помощью функции 1еп). Последняя сталильнал версия. — Примеч.
науч.ред. Закрепление пройденного 2. 3. 4. 5. ° Функцию соипгСпага(паве), которая читает входной файл и подсчитывает число символов в нем (подсказка: метод (11е. геао возвращает единую строку). ° Функцию геаг(паве), которая вызывает две предыдущие функции с заданным именем файла. Вообще говоря, имя файла можно жестко определить в программном коде, принимать ввод имени от пользователя или принимать его как параметр командной строки через список ауа, а гзэ,— но пока исходите из предположения, что оно передается как аргумент функции.
Все три функции в модуле вузов должны принимать имя файла в ви- де строки. Если размер любой из функций превысит две-три стро- ки, это значит, что вы делаете лишнюю работу, — используйте под- сказки, которые я вам дал! Затем проверьте свой модуль в интерактивной оболочке„используя инструкцию 1зрогг и полные имена экспортируемых функций. Сле- дует ли добавить в переменную РУТНОМРАТН каталог, где находится ваш файл тутод.ру"г Попробуйте проверить модуль на самом себе: например, Геа((тяуаог), ру"). Обратите внимание, что функция ГеаГ открывает файл дважды — если вы достаточно честолюбивы, попро- буйте оптимизировать программный код, передавая двум функци- ям счета объект открытого файла (подсказка: метод (11е, вееМ(0) вы- полняет переустановку указателя в начало файла), Г гоп/агап *.
Проверьте модуль зуасс из упражнения 1 в интерактив- ной оболочке, используя для загрузки экспортируемых имен инст- рукцию Г гоп — сначала по имени, а потом с помощью формы г гоа *. тот . Добавьте в модуль пуаог) строку, в которой автоматиче- ски производился бы вызов функции гсвг, только когда модуль вы- полняется как самостоятельный сценарий, а не во время импорти- рования. Добавляемая вами строка, вероятно, должна содержать проверку значения атрибута паве на равенство строке " аа(п,", как было показано в этой главе. Попробуйте запустить модуль из системной командной строки, затем импортируйте модуль и про- верьте работу функций в интерактивном режиме. Будут ли рабо- тать функции в обоих режимаху Вложенное импортирование.