Главная страница
Навигация по странице:

  • История о трех программах

  • Придется держать в уме: пакеты модулей

  • Закрепление пройденного Контрольные вопросы

  • Сокрытие данных в модулях

  • Минимизация повреждений, причиняемых инструкцией from *: _X и __all__

  • Математический анализ. 3е издание


    Скачать 4.86 Mb.
    Название3е издание
    АнкорМатематический анализ
    Дата04.02.2022
    Размер4.86 Mb.
    Формат файлаpdf
    Имя файлаpython_01.pdf
    ТипДокументы
    #351981
    страница64 из 98
    1   ...   60   61   62   63   64   65   66   67   ...   98
    dir2.mod
    NameError: name 'dir2' is not defined
    >>> mod.z
    NameError: name 'mod' is not defined
    Поэтому для импортирования пакетов часто более удобно использо
    вать инструкцию from, чтобы избежать необходимости ввода полного имени при каждом обращении к нему. Пожалуй, еще более важно, что

    Зачем используется операция импортирования пакетов?
    527
    если вы когданибудь выполните реструктуризацию дерева каталогов,
    то в случае использования инструкции from достаточно будет обновить только саму инструкцию, тогда как в случае использования инструк
    ции import придется обновлять все обращения к именам в изменив
    шемся пакете. Расширение import as, обсуждаемое в следующей главе,
    поможет вам определить сокращенные синонимы для полных путей:
    % python
    >>> from dir1.dir2 import mod # Описание пути находится только в этом месте
    dir1 init dir2 init in mod.py
    >>> mod.z # Указывать полный путь не требуется
    3
    >>> from dir1.dir2.mod import z
    >>> z
    3
    >>> import dir1.dir2.mod as mod # Использование короткого синонима
    >>> mod.z
    3
    Зачем используется операция
    импортирования пакетов?
    Если вы только начинаете осваивать язык Python, то прежде чем пере
    ходить к использованию пакетов, вам сначала необходимо освоить ра
    боту с простыми модулями. Пакеты действительно являются полез
    ным инструментом, особенно в крупных программах: они делают опе
    рацию импортирования более информативной, выступают в роли орга
    низационного инструмента, упрощают поиск файлов модулей и способны разрешать возникающие неоднозначности.
    Так как операция импортирования пакетов содержит некоторые сведе
    ния о структуре каталогов, где находятся файлы программы, они,
    в первую очередь, упрощают поиск файлов и служат организационным инструментом. Не имея информации о путях к пакетам, вам часто при
    шлось бы обращаться к содержимому пути поиска модулей, чтобы оты
    скать требуемые файлы. Кроме того, если вы организовали размещение своих файлов в дереве каталогов по функциональным признакам, то операция импортирования пакетов делает более очевидной роль, кото
    рую играют пакеты, что обеспечивает более высокую удобочитаемость программного кода. Например, обычная операция импорта файла в ка
    талоге, находящемся гдето в пути поиска модулей, выглядит так:
    import utilities предлагая намного меньше информации, чем операция импорта,
    включающая путь к модулю:
    import database.client.utilities

    528
    Глава 20. Пакеты модулей
    Операция импортирования пакетов может также упростить задание переменной окружения PYTHONPATH и файлов .pth, хранящих настройки пути поиска модулей. Фактически, если вы используете импортирова
    ние пакетов для всех имеющихся каталогов, где хранится ваш про
    граммный код, и импорт производится относительно общего корнево
    го каталога, вам достаточно будет добавить единственную запись в путь поиска модулей: общий корневой каталог. Наконец, операция импортирования пакетов способна разрешать неоднозначности за счет явного и точного указания импортируемых файлов. В следующем раз
    деле эта роль исследуется более подробно.
    История о трех программах
    Единственный случай, когда операция импортирования действитель
    но необходима, – это разрешение неоднозначностей, которые могут возникать, когда на одной машине установлено множество программ,
    содержащих файлы с одинаковыми именами. В определенной степени это проблема установки программ, но она может стать источником бес
    покойств в обычной практике. Давайте рассмотрим гипотетическую ситуацию, чтобы проиллюстрировать эту проблему.
    Предположим, что программист разработал программу на языке Py
    thon, которая содержит файл именем utilities.py, хранящий вспомога
    тельный программный код, и файл main.py, используемый для запус
    ка программы. Все файлы программы вызывают инструкцию import utilities для загрузки и использования общего программного кода.
    Программа распространяется в виде единого архива в формате .tar или
    .zip
    , содержащего все файлы программы, и при установке все файлы распаковываются в единственный каталог с именем system1:
    system1\
    utilities.py # Общие вспомогательные функции, классы
    main.py # Этот файл запускает программу
    other.py # Импортирует и использует модуль utilities
    Теперь предположим, что другой программист разработал другую про
    грамму, в которой также имеются файлы utilities.py и main.py, и так
    же используется инструкция import utilities во всех файлах програм
    мы для загрузки общего программного кода. Во время установки этой второй программы на том же самом компьютере, где уже была уста
    новлена первая программа, ее файлы были распакованы в новый ката
    лог с именем system2, чтобы не перезаписать одноименные файлы пер
    вой программы:
    System2\
    utilities.py # Общие вспомогательные функции
    main.py # Этот файл запускает программу
    other.py # Импортирует модуль utilities
    Пока что никаких явных проблем не наблюдается: обе программы пре
    красно сосуществуют и работают на одной и той же машине. Фактиче

    Зачем используется операция импортирования пакетов?
    529
    ски для этих программ вам даже не нужно настраивать путь поиска мо
    дулей, потому что интерпретатор всегда начинает поиск модулей с до
    машнего каталога программы (то есть с каталога, в котором находится главный файл программы), операции импортирования в любой из этих программ автоматически будут находить все необходимые файлы в до
    машнем каталоге программы. Например, если запускается файл sys+
    tem1\main.py
    , все операции импортирования сначала будут просматри
    вать каталог system1. Точно так же при запуске файла system2\main.py
    в первую очередь будет просматриваться каталог system2. Не забывай
    те, что настраивать путь поиска модулей необходимо только при необ
    ходимости импортировать модули из разных каталогов.
    А теперь предположим, что после установки этих двух программ вы ре
    шили использовать вспомогательные функции из обоих файлов utili+
    ties.py
    в своей собственной программе. В конце концов, это обычный вспомогательный программный код, а для программного кода на языке
    Python вполне естественно, когда он используется многократно. В та
    кой ситуации вам необходима возможность из своего программного ко
    да, хранящегося в третьем каталоге, загрузить один из двух файлов:
    import utilities utilities.func('spam')
    Теперь проблема начинает вырисовываться. Чтобы вообще выполнить эту работу, вам придется включить в путь поиска модулей каталоги,
    содержащие файлы utilities.py. Но какой каталог поместить первым –
    system1
    или system2?
    Проблема заключается в линейной природе пути поиска. Он всегда просматривается слева направо. Независимо от того, как долго вы бу
    дете ломать голову над этой проблемой, вы всегда будете получать файл utilities.py из каталога, который находится в пути поиска раньше
    (левее). Как следствие, вы никогда не сможете импортировать одно
    именный файл из другого каталога. Вы можете попытаться изменять sys.path в своей программе перед каждой операцией импортирования,
    но это сложная работа и при ее выполнении легко ошибиться. По умолчанию проблема оказывается для вас неразрешимой.
    Эту проблему можно решить с помощью пакетов. Вместо того чтобы устанавливать программы как плоские списки файлов в независимые каталоги, можно установить их в подкаталоги с общим корнем. На
    пример, можно было бы организовать установку всего программного кода из этого примера в виде следующей иерархии:
    root\
    system1\
    __init__.py utilities.py main.py other.py system2\

    530
    Глава 20. Пакеты модулей
    __init__.py utilities.py main.py other.py system3\ # Здесь или в другом месте
    __init__.py # располагается ваш новый программный код
    myfile.py
    Теперь достаточно просто добавить общий корневой каталог в путь по
    иска модулей. Если теперь выполнять импортирование относительно этого общего корня, можно будет с помощью операции импортирова
    ния пакетов импортировать любой файл из любой программы – ис
    пользование имени вмещающего каталога делает путь (а значит,
    и ссылку на модуль) уникальным. Фактически можно даже импорти
    ровать обе утилиты сразу в одном и том же модуле, при условии, что вы будете использовать инструкцию import и при каждом обращении к именам будете указывать полный путь к вспомогательным модулям:
    import system1.utilities import system2.utilities system1.utilities.function('spam')
    system2.utilities.function('eggs')
    В данном случае имя вмещающего каталога обеспечивает уникаль
    ность ссылок на модули.
    Обратите внимание, что вместо инструкции from необходимо использо
    вать инструкцию import, только если вам необходимо получить доступ к двум или более одноименным атрибутам. Если бы имена вызывае
    мых здесь функций различались, можно было бы использовать инст
    рукцию from, чтобы избежать необходимости всякий раз вводить пол
    ные пути к пакетам, как уже описывалось выше.
    Кроме того, следует заметить, что в приведенной выше иерархии уста
    новки файлы _ _init_ _.py были добавлены в каталоги установки про
    грамм system1 и system2, но не в корневой каталог root. Этот файл тре
    буется помещать только в каталоги, перечисленные в инструкциях im
    port
    , – как вы наверняка помните, они автоматически выполняются интерпретатором при первой попытке программы импортировать ка
    талог пакета.
    С точки зрения реализации, каталог system3 не обязательно должен находиться в каталоге root – здесь должны находиться только катало
    ги, откуда производится импорт пакетов. Однако, поскольку ваши собственные модули могут когданибудь быть использованы в других программах, было бы желательно поместить их в общий корневой ка
    талог, чтобы избежать подобных проблем в будущем.
    Наконец, обратите внимание, что операции импорта в обеих оригиналь
    ных программах продолжают действовать без изменений. Поскольку в этих программах поиск модулей производится в первую очередь в их
    домашних
    каталогах, добавление общего корневого каталога в путь по

    В заключение
    531
    иска модулей никак не отражается на программном коде в system1
    и system2 – они попрежнему могут использовать инструкции import utilities и ожидать получить в ответ свои собственные файлы. Кроме того, если вы предусмотрительно будете устанавливать все программы на языке Python в общий корневой каталог, как в данном примере, на
    стройка пути поиска станет элементарной: вам достаточно будет один раз добавить в него общий корневой каталог.
    В заключение
    В этой главе была представлена модель импортирования пакетов – не
    обязательный, но удобный способ явно указать путь к каталогам с мо
    дулями. В инструкциях импорта указывается путь относительно ката
    лога, находящегося в пути поиска модулей, но вместо того, чтобы по
    лагаться на результаты поиска, выполняемого интерпретатором, ва
    ши сценарии могут явно указывать остаток пути к модулю.
    Как мы видели, пакеты не только делают операцию импортирования бо
    лее осмысленной в крупных программах, но еще и упрощают настройку пути поиска (если все каталоги, откуда производится импорт, вложены
    Придется держать в уме: пакеты модулей
    Теперь, когда пакеты стали стандартной частью Python, часто можно встретить крупные расширения сторонних разработчи
    ков, распространяемые не как плоский список модулей, а как на
    бор каталогов с пакетами. Например, пакет расширений win32all
    для Python в операционной системе Windows был одним из пер
    вых, кто перешел на сторону победителя. Многие вспомогатель
    ные модули этого пакета располагаются в пакетах, импортируе
    мых посредством указания пути. Например, чтобы загрузить на
    бор инструментальных средств для работы с технологией COM на стороне клиента, можно использовать такую инструкцию:
    from win32com.client import constants, Dispatch
    Эта инструкция извлекает имена из модуля client в пакете win32com
    (подкаталог, куда был установлен пакет).
    Импортирование пакетов повсеместно используется в программ
    ном коде, работающем под управлением Jython, – реализации языка Python на Java, потому что библиотеки самого языка Java тоже организованы в виде иерархии каталогов. В последних вер
    сиях Python инструменты для работы с электронной почтой и XML в стандартной библиотеке также были организованы в подкаталоги пакетов. Если вы создаете каталоги пакетов, в ко
    нечном итоге у вас будет возможность импортировать их.

    532
    Глава 20. Пакеты модулей в один общий корневой каталог), а также позволяют разрешать возни
    кающие неоднозначности в тех случаях, когда существует более одного модуля с одним и тем же именем (наличие имен каталогов в операциях импортирования позволяет обеспечить уникальность имен модулей).
    В следующей главе мы исследуем несколько более сложных тем,
    имеющих отношение к модулям, таких как синтаксис относительного импорта и переменная режима использования __name__. Как обычно,
    мы заканчиваем эту главу серией контрольных вопросов, чтобы прове
    рить, насколько хорошо вы запомнили сведения, полученные здесь.
    Закрепление пройденного
    Контрольные вопросы
    1. Для чего служит файл _ _init_ _.py в каталогах пакетов модулей?
    2. Как избежать необходимости снова и снова вводить полное имя па
    кета при каждом обращении к содержимому пакетов?
    3. В каких каталогах необходимо создавать файл _ _init_ _.py?
    4. В каких случаях вместо инструкции from приходится использовать инструкцию import?
    Ответы
    1. Файлы _ _init_ _.py служат для объявления и инициализации па
    кета, – интерпретатор автоматически запускает программный код в этих файлах, когда каталог импортируется программой впервые.
    Переменные, которым выполняется присваивание в этих файлах,
    становятся атрибутами объекта модуля для соответствующего ката
    лога. Присутствие этих файлов в каталогах пакетов обязательно –
    вы не сможете импортировать пакеты при отсутствии этих файлов в каталогах.
    2. Используйте инструкцию from, чтобы скопировать имена из пакета или воспользуйтесь расширением as инструкции import, чтобы пе
    реименовать полный путь в короткий синоним. В обоих случаях полный путь будет присутствовать только в одном месте – в инст
    рукции from или import.
    3. Каждый каталог, перечисленный в инструкции import или from,
    должен содержать файл _ _init_ _.py. Другие каталоги, включая ка
    талог, содержащий самый первый компонент пути к пакету, не тре
    буют наличия этого файла.
    4. Инструкция import должна использоваться вместо инструкции from,
    только если вам необходимо обеспечить доступ к одному и тому же имени более чем в одном каталоге. Благодаря инструкции import употребление полного пути обеспечивает уникальность ссылок, то
    гда как инструкция from допускает наличие только одной версии любого имени.

    21
    Дополнительные возможности модулей
    Эта глава завершает пятую часть книги, представляя коллекцию бо
    лее сложных тем, имеющих отношение к модулям, – синтаксис отно
    сительного импорта, сокрытие данных, модуль __future__, переменная
    __name__
    , изменение списка sys.path и т. д. и, кроме того, содержит пе
    речень наиболее типичных ошибок и упражнения, завершающие эту часть книги. Как и функции, модули наиболее эффективны, когда должным образом определены их интерфейсы, поэтому в данной главе представлен краткий обзор концепций проектирования модулей, не
    которые из которых мы исследовали в предыдущих главах.
    Несмотря на слово «дополнительные» в заглавии этой главы, некото
    рые из обсуждаемых здесь возможностей (такие, как приемы работы с переменной __name__) используются достаточно широко, поэтому обя
    зательно ознакомьтесь с ними, прежде чем переходить к классам в сле
    дующей части книги.
    Сокрытие данных в модулях
    Как мы уже видели, модули в языке Python экспортируют все имена,
    которым были присвоены значения на верхнем уровне файлов. В язы
    ке нет никаких объявлений, которые позволили бы сделать одни име
    на видимыми, а другие – невидимыми за пределами модуля. Фактиче
    ски нет никакого способа предотвратить возможность изменения имен в модуле извне, если в этом появится необходимость.
    Сокрытие данных модуля в языке Python регулируется соглашения
    ми, а не синтаксическими конструкциями. Если задаться целью по
    вредить модуль, изменяя имена в нем, вам ничто не сможет помешать,
    но, к счастью, я еще не встречал программистов, кто стремился бы это сделать. Некоторые пуристы возражают против такого либерального отношения к сокрытию данных, утверждая в связи с этим, что в языке

    534
    Глава 21. Дополнительные возможности модулей
    Python отсутствует возможность инкапсуляции. Инкапсуляция в язы
    ке Python скорее относится к организации пакетов, чем к возможно
    сти накладывать ограничения.
    Минимизация повреждений, причиняемых
    инструкцией from *: _X и __all__
    Как особый случай, существует возможность начинать имена перемен
    ных с одного символа подчеркивания (например, _X), чтобы предотвра
    тить их перезаписывание, когда клиент выполняет импортирование модуля инструкцией from *. Этот прием на самом деле предназначен только для минимизации загрязнения пространства имен – так как инструкция from * копирует все имена, импортирующий модуль мо
    жет получить больше, чем предполагал (включая имена, которые пе
    резапишут имена импортирующего модуля). Символы подчеркивания не являются объявлением «частных» данных: вы попрежнему може
    те видеть эти имена и изменять их с помощью других форм импорти
    рования, таких как инструкция import.
    Альтернативный способ достижения эффекта сокрытия данных, напо
    минающий соглашение об именовании _X, заключается в присвоении на верхнем уровне модуля переменной __all__ списка строк с именами переменных. Например:
    __all__ = ["Error", "encode", "decode"] # Экспортируются только эти имена
    При использовании этого приема инструкция from * будет копировать только имена, перечисленные в списке __all__. В действительности это соглашение, обратное соглашению _X: переменная __all__ идентифи
    цирует имена, доступные для копирования, тогда как соглашение _X
    идентифицирует имена, недоступные для копирования. Интерпрета
    тор Python сначала отыскивает список __all__ в модуле, и если он от
    сутствует, инструкция from * копирует все имена, которые не начина
    ются с единственного символа подчеркивания.
    Подобно соглашению _X, список __all__ имеет смысл только для инст
    рукции from * и не является объявлением частных данных. Програм
    мисты могут использовать при реализации модулей любой из этих приемов, которые хорошо работают с инструкцией from *. (Смотрите также обсуждение списков __all__ в файлах пакетов __init__.py в гла
    ве 20 – там эти списки объявляют субмодули, которые могут быть за
    гружены инструкцией from *.)
    1   ...   60   61   62   63   64   65   66   67   ...   98


    написать администратору сайта