Лутц М. - Изучаем Python (1077325), страница 108
Текст из файла (страница 108)
Рассмотрим пример модуля а)т)з1еззу: ргтпг 'Пемо' прав = 1 В Инициализировать переменнуа В этом примере инструкции рг1Ш и = выполняются при первой операции импортирования модуля, и переменная прав инициализируется во время импортирования: % ру1поп »> зарогг аьвр1е а Первая инструкция змрогг, загрумает а и запускает код модуля пе11о »> в1вр1е,прав а Операция присваивания создает атрибут 505 Использование модулей Вторая и все последующие операции импортирования не приводят к перезапуску программного кода модуля — они просто получают объ- ект модуля из внутренней таблицы модулей интерпретатора. В резуль- тате повторная инициализация переменной врав не происходит: З Изиенить атрибут иодуля З Просто полунзет уже загруженньй иодуль З Код не перезапускается: атрибут не изиенился »> в1вр1в.врвв = 2 »> 1арогт в1вр1в >» 41ар1в.
врвв 2 Конечно, иногда действительно бывает необходимо перезапустить программный код модуля при повторных операциях импортирования. Позднее в этой главе мы увидим, как это можно сделать с помощью функции ге! озо. х=з у=Гп 23 % рутьоп »> ггоа ваап 1врог1 х, у з скопировать цеа имени »> х = 42 З Изиеняется тол~ко локальная переменная к »> у~б) = 42 З Изменяется непосредственно изиеняеиий обьект Здесь х не является разделяемым изменяемым объектом, а вот у — яв- ляется. Имена у в импортирующем и импортируемом модулях ссыла- ются на один и тот же объект списка, поэтому изменения, произведен- ные в одном модуле, будут видны в другом модуле: Инструкции ппрог1 и гогот — операции присваивания Так же, как и инструкция бег, инструкции зврогг и тгов являются выполняемыми инструкциями, а не объявлениями времени компиляции.
Они могут вкладываться в условные инструкции зг, присутствовать в объявлениях функций беу и т. д., и они не имеют никакого эффекта, пока интерпретатор не достигнет их в ходе выполнения программы. Другими словами, импортируемые модули и имена в них не будут доступны, пока не будут выполнены соответствующие инструкции 1врогг или т гав. Кроме того, подобно инструкции бег, 1врогг и бгов— это явные операции присваивания: ° Инструкция зврогг присваивает ссылку на объект модуля единственной переменной. ° Инструкция бгов присваивает одно или более имен объектам с теми же именами в другом модуле.
Все, что уже обсуждалось ранее, в равной степени применимо и к модулям. Например, имена, копируемые инструкцией усов, становятся ссылками на разделяемые объекты — как и в случае с аргументами функций, переприсваивание полученному имени не оказывает воздействия на модуль, откуда это имя было скопировано, но изменение изменяемого объекта может оказывать воздействие на объект в модуле, откуда он был импортирован.
Для иллюстрации рассмотрим следующий файл втаяру: 506 Чтобы увидеть графическое изображение того, что делает со ссылками инструкция Ггоа, вернитесь к рис. 16.2 (передача аргументов функциям) и мысленно замените слова «вызывающая программа» и «функция» на «импортируемый модуль» и «импортирующий модуль». Эффект тот же самый, за исключением того, что здесь мы имеем дело с именами в модулях, а не с функциями. Операция присваивания везде в языке Ру1ьоп работает одинаково. Изменение значений имен в других файлах Вспомним, что в предыдущем примере присваивание переменной х в интерактивной оболочке изменяло ее значение только в этой области видимости и не оказывало влияния на переменную х в файле — между именем, скопированным инструкцией Ггов, и именем в файле, откуда это имя было скопировано, нет никакой связи.
Чтобы действительно изменить глобальное имя в другом файле, необходимо использовать инструкцию!врет!: % рутвоп »> Ггов вваП !врос! х, У »> х = 42 В Скопировать два имени Ф Изменить тол~ко локальное иия х »> 1арог! вааП »> вааП .х = 42 я Получить иия модуля В Изиенить х в другои модуле Это явление было описано в главе 16. Поскольку изменение переменных в других модулях, как в данном случае, часто является источником проблем (и следствием неудачного проектирования), мы еще вернемся к этому приему позднее в этой части книги.
Обратите внимание, что изменение элемента у(0] в предыдущем примере — это нечто иное; изменяется объект, а не имя. Эквивалентность инструкций! трог~ и Фгогл Обратите внимание: в предыдущем примере после инструкции ггоа нам потребовалось выполнить инструкцию !арогг, чтобы получить доступ к имени модуля ваа11, — инструкция ! гоа копирует только имена из одного модуля в другой и ничего не присваивает самому имени модуля.
Инструкция Ггоа, приведенная ниже: ггоа аооо1е !арогт паве!, паае2 а копировать тол~ко зги два ииени эквивалентна следующей последовательности, по крайней мере,кон- цептуально: тарог! аоло1е В Получит~ обьект иодуля »> 1врог! вваП »> вавы.х 1 »> вваП,У (42, 2] Глава !9. Основы программирования модулей в получить имя иодуля (инструкция ггоа его не дает) а х в заа11 — зто не иоя леременная х В По изиеняеиия обьект используется совиестно Использование модулей 507 я Скопировать имена с помощью присваивания Ф удалить имя модуля паае1 = аООи1е пааеп паае2 = аопи1е.паае2 Ое1 попо!е Как и все операции присваивания, инструкция ггоа создает новые переменные в импортирующем модуле, которые ссылаются на объекты с теми же именами в импортируемом файле.
При этом копируются только имена, а не сам модуль. При использовании формы 1гоа * этой инструкции (1гоа асс!с1е 1арог1 *) эквивалентная последовательность действий та же самая, только при этом копируются все имена, определенные на верхнем уровне импортируемого модуля. Обратите внимание, что на первом шаге инструкция 1гоа выполняет обычную операцию тарсг1. Вследствие этого инструкция ггоа всегда импортирует весь модуль целиком, если он еще не был импортирован, независимо от того, сколько имен копируется из файла. Нет никакой возможности загрузить только часть модуля (например, только одну функцию), но так как модули — это байт-код, а не машинный код, влияние на производительность оказывается незначительным.
Потенциальные проблемы инструкции Фгот Инструкция (гоа делает местоположение переменных менее явным и очевидным (имя паве несет меньше информации, чем аодо1е, паве), поэтому некоторые пользователи Ру()юп рекомендуют использовать инструкцию таро г1 вместо ггоа. Однако я не уверен, что это такой уж однозначный совет: инструкция 1гоа используется достаточно часто и без каких- либо страшных последствий. На практике часто бывает удобно избавиться от необходимости набирать имя модуля всякий раз, когда требуется использовать один из его инструментов. Это особенно справедливо для крупных модулей, которые предоставляют большое число атрибутов, таких как модуль ТХ1п1е г из стандартной библиотеки, например.
Суть проблемы состоит в том, что инструкция ггоа способна повреждать пространства имен, по крайней мере, в принципе — если использовать ее для импортирования переменных, когда существуют одноименные переменные в имеющейся области видимости, то эти переменные просто будут перезаписаны. Эта проблема отсутствует при использовании инструкции таро г1, потому что доступ к содержимому импортируемого модуля возможен только через его имя (имя аоо о1е, агг г не конфликтует с именем а11г в текущей области видимости). Пока вы понимаете и контролируете все, что может происходить при использовании инструкции ггса, во всем этом нет большой проблемы, особенно если импортируемые имена указываются явно(например, 1гоа асср1е !арог1 х, у, 2). С другой стороны, инструкция ггса скрывает в себе более серьезные проблемы, когда используется в комбинации с функцией ге1оаС, т.
к. импортированные имена могут ссылаться на предыдущие версии объектов. Кроме того, инструкция в форме 1гоа аобо1е !прог! * действительно может повреждать пространства имен и затрудняет понимание 508 Глава )оь Основы программирования модулей имен, особенно когда она применяется более чем к одному файлу. В этом случае нет никакого способа определить, какому модулю принадлежит то или иное имя, разве только выполнить поиск по файлам с исходными текстами. В действительности форма Г гое * вставляет одно пространство имен в другое, что сводит на нет преимущества, которые несет возможность разделения пространств имен.
Мы будем рассматривать эти проблемы более подробно в разделе»Типичные ошибки при работе с модулями» в конце этой части книги (глава 21). Пожалуй, лучший совет, который можно дать, — в общем отдавать предпочтение инструкции 1ерог( для простых модулей, явно перечислять необходимые переменные в инструкциях Ггое и не использовать форму Г гсе * для импорта более чем одного файла в модуле. При таком подходе можно предполагать, что все неопределенные имена располагаются в модуле, к которому обращались через инструкцию Ггое *. При работе с инструкцией (гсе, конечно, следует проявлять осторожность, но, вооруженные знаниями, большинство программистов находят ее удобной для организации доступа к модулям.
Когда необходимо использовать инструкцию ппрогт а м.ру оег гцпс(): ... Вмполнить что- то одно... № М ОУ оег гцпс(): ...выполнить что-то другое... и необходимо использовать обе версии имени в программе. В этом слу- чае инструкцию Ггое использовать нельзя, потому что в результате вы получите единственное имя в вашей области видимости: № О.ру Ггсе М шерагт Гцпс ггсе М герогт Гцпс гцпс() № Перезапишет имя, иипортированное из иодупя М № будет вмзвана Л. Тцпс Зато можно использовать инструкцию терогт, потому что включение имени вмещающего модуля сделает имена уникальными: В О.ру 1ерсгт М, М М Гцпс() М.топо() № Получить модул~ целиком, а не отдел»иве имена № теперь мошно вмзивать обе функции № Наличие имени модуля делает ик уникальнмии Этот случай достаточно необычен, поэтому вы вряд ли часто будете сталкиваться с ним на практике.
Единственное, когда необходимо вместо инструкции Ггсе использо- вать инструкцию 1ерсгг, — когда требуется использовать одно и то же имя, присутствующее в двух разных модулях. Например, когда два файла по-разному определяют одно и то же имя: 509 Пространства имен модулей Пространства имен модулей Модули будут, вероятно, более понятны, если представлять их, как простые пакеты имен — то есть место, где определяются переменные, которые должны быть доступны остальной системе. С технической точки зрения каждому модулю соответствует отдельный файл, и интерпретатор создает объект модуля, содержащий все имена, которым присвоены какие-либо значения в файле модуля.