Выполнение модулей как скриптов. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Выполнение модулей как скриптов.



Когда вы запускаете модуль Python командой

python fibo.py <arguments>

код в модуле будет выполнен, просто как если бы вы импортировали его, но с __name__, установленным в "__main__". Это означает, что при добавлении этого кода в конец вашего модуля

if __name__ == "__main__": import sys fib(int(sys.argv[1]))

вы можете сделать файл используемым как скрипт, в то же время он останется импортируемым модулем, потому что код, который разбирает командную строку, запускается только, если модуль выполняется как файл "main":

$ python fibo.py 501 1 2 3 5 8 13 21 34

Если модуль импортируется, то код не выполняется:

>>> import fibo>>>

Это часто используется либо для обеспечения удобного пользовательского интерфейса к модулю, либо для целей тестирования (при запуске модуля как скрипта выполняется ряд тестов).

Путь поиска модуля.

Когда осуществляется импорт модуля по имени spam, сначала интерпретатор ищет встроенные модули с таким именем. Если не находит, то затем ищет файл по имени spam.py в списке каталогов, заданных переменной sys.path. sys.path инициируется из этих мест:

· Каталог, содержащий выполняемый скрипт (или текущий каталог, когда не указан никакой файл).

· PYTHONPATH (список имен каталогов, с таким же синтаксисом как переменная оболочки PATH).

Умолчания, зависимые от установки.

Примечание: В файловой системе, которая поддерживает символические ссылки, каталог, содержащий запущенный скрипт, обрабатывается после символической ссылки. Другими словами, каталог, содержащий символическую ссылку, не добавляется к пути поиска модуля.

После инициализация программа на Python может изменить sys.path. Директория, содержащая запущенный скрипт, размещается в начале пути поиска, впереди пути стандартной библиотеки. Это означает, что скрипты из данной директории будут загружены вместо модулей с такими же именами в каталоге библиотеки. Если замена не предполагалась, то это ошибка.

"Скомпилированные" файлы Python.

Для ускорения загрузки модулей Python кэширует скомпилированную версию каждого модуля в каталоге __pycache__ под именем module.version.pyc, где версия кодирует формат скомпилированного файла; обычно включает номер версии Python. Например, в CPython релизе 3.3 скомпилированная версия была бы кэширована как __pycache__/spam.cpython-33.pyc. Такое соглашение наименования позволяет компилировать модули из различных релизов и различных версий Python для сосуществования.

Python сравнивает дату изменения исходного кода со скомпилированной версией, чтобы обнаружить, если она устарела и нуждается в перекомпиляции. Это полностью автоматический процесс. Также скомпилированные модули не зависят от платформы, так одна и та же библиотека может быть разделена среди систем с различными архитектурами.

Python не проверяет кэш в двух случаях. Во-первых, он всегда перекомпилирует и не хранит результат для модуля, который загружается прямо из командной строки. Во вторых, он не проверяет кэш, если нет исходного кода модуля. Для поддержки распространения без исходного кода скомпилированный модуль должен быть в каталоге с исходными кодами, и здесь не должно быть исходных кодов модуля.

Стандартные модули.

Python поставляется с библиотекой стандартных модулей, описанных в отдельном документе, Справка по библиотеке Python. Несколько модулей встроено в интерпретатор; они предоставляют доступ к операциям, которые не являются частью ядра языка, но тем не менее встроены в него, либо для повышения эффективности, либо для обеспечения доступа к примитивам операционной системы, таким как системные вызовы. Установка таких модулей является конфигурационной опцией, которая также зависит от используемой платформы. Например, модуль winreg предоставляется только на системах Windows. Один особый модуль заслуживает внимания: sys, который встроен в каждый интерпретатор Python. Переменные sys.ps1 и sys.ps2 определяют строки, используемые как первичное и вторичное приглашения:

>>> import sys>>> sys.ps1 '>>> ' >>> sys.ps2 '... ' >>> sys.ps1 = 'C> ' C> print('Yuck!')Yuck!C>

Эти две переменные определены, только если интерпретатор в интерактивном режиме.

Переменная sys.path является списком строк, который определяет путь поиска модулей интерпретатора. Он инициируется путем по умолчанию, взятым из переменной окружения, или из встроенного по умолчанию, если PYTHONPATH не установлена. Вы можете изменить ее, используя стандартный список операций:

>>> import sys>>> sys.path.append('/ufs/guido/lib/python')

 

Функция dir().

Функция dir() используется для выяснения, какие имена модулей определены. Она возвращает отсортированный список строк:

>>> import fibo, sys>>> dir(fibo)[ '__name__', 'fib', 'fib2' ]>>> dir(sys) [ '__displayhook__', '__doc__', '__excepthook__', '__loader__', '__name__', '__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_getframe', '_home', '_mercurial', '_xoptions', 'abiflags', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding', 'getobjects', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettotalrefcount', 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'ps1', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdout', 'thread_info', 'version', 'version_info', 'warnoptions' ]

Без аргументов dir() перечисляет имена, которые вы определили в настоящее время:

>>> a = [1, 2, 3, 4, 5]>>> import fibo>>> fib = fibo.fib>>> dir()[ '__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys' ]

Заметьте, что она перечисляет все типы имен: переменные, модули, функции и т. д.

dir() не перечисляет имена встроенных функций и переменных. Если вы хотите получить их список, они определены в стандартном модуле builtins (docs.python.org/3/library/builtins.html#module-builtins):

>>> import builtins>>> dir(builtins) [ 'ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip' ]

 

 

Пакеты.

Пакеты являются способом структурирования пространства имен Python с помощью "точечных имен модулей". Например, имя модуля A.B обозначает подмодуль с именем B в пакете с именем A. Такое использование модулей позволяет разработчикам различных модулей не беспокоится об именах глобальных переменных друг друга, использование точечных имен модулей позволяет авторам мультимодульных пакетов, таких как NumPy или Python Imaging Library, не беспокоиться об именах модулей друг друга.

Предположим, вы хотите разработать коллекцию модулей ("пакет") для единообразной обработки звуковых файлов и звуковых данных. Существует множество различных форматов звуковых файлов (обычно распознаваемых по их расширению, например:.wav,.aiff,.au), поэтому вам может потребоваться создавать и поддерживать растущую коллекцию модулей для конверсии между различными форматами файлов. Есть также множество различных операций, которые можно выполнять над звуковыми данными (такие как смешивание, добавление эхо, применение функции эквалайзера, создание искусственного стерео-эффекта), поэтому в дополнение вы будете писать нескончаемый поток модулей для выполнения этих операций. Здесь возможная структура для вашего пакета (выраженная в терминах иерархической файловой системы):

sound/                     Пакет верхнего уровня    __init__.py          Инициализирует звуковой пакет formats/             Подпакет для конверсии файловых форматов         __init__.py         wavread.py         wavwrite.py         aiffread.py         aiffwrite.py         auread.py         auwrite.py        ... effects/             Подпакет для звуковых эффектов         __init__.py         echo.py         surround.py         reverse.py        ...    filters/             Подпакет для фильтров         __init__.py         equalizer.py         vocoder.py         karaoke.py        ...

При импорте пакета Python просматривает каталоги в соответствии с sys.path для обнаружания подкаталога пакета.

Файлы __init__.py требуются для того, чтобы Python обрабатывал каталоги как содержащие пакеты; это делается для предотвращения, что каталоги с обычными именами, такими как string, не будут непреднамеренно скрывать действительные модули, которые обнаружатся позже по пути поиска модулей. В самом простом случае __init__.py может просто быть пустым файлом, но он также может выполнять инициализирующий код для пакета или устанавливать переменную __all__, описанную позже.

Пользователи пакета могут импортировать индивидуальные модули из пакета, например:

import sound.effects.echo

Загружается подмодуль sound.effects.echo. На него надо ссылаться по его полному имени:

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

Альтернативный способ импорта подмодуля:

from sound.effects import echo

Также загружается подмодуль echo, но он доступен без его пакетного префикса, поэтому он может быть использован так:

echo.echofilter(input, output, delay=0.7, atten=4)

Еще одним вариантом является непосредственный импорт нужной функции или переменной:

from sound.effects.echo import echofilter

Опять же такой импорт загружает подмодуль echo, но это делает его функцию echofilter() доступной напрямую:

echofilter(input, output, delay=0.7, atten=4)

Заметьте, что когда используется from package import item, item может быть либо подмодулем (или подпакетом) пакета, либо каким-нибудь другим именем, определенным в пакете, как функция, класс или переменная. Оператор import сначала проверяет, есть ли определенный элемент в пакете; если нет, он предполагает, что это модуль и пытается загрузить его. Если он не находится, возбуждается исключение ImportError.

Наоборот, когда используется синтаксис как import item.subitem.subsubitem, каждый элемент исключается, и последний должен быть пакетом; последний элемент может быть модулем или пакетом, но не может быть классом или функцией или переменной, определенными в предыдущем элементе.

Импортирование * из пакета.

Теперь что случится, когда пользователь напишет sound.effects import *? Хотелось бы надеяться, что в идеале это как-нибудь выходит на файловую систему, находит, какие подмодули есть в пакете, и импортирует их все. Это может занять долгое время и импортирование подмодулей может иметь нежелательный побочный эффект, который должен происходить только, когда подмодули явно импортированы.

Для разработчика пакета есть только одно решение обеспечить явное индексирование пакета. Оператор import использует следующее соглашение: если код __init__.py пакета определяет список под названием __all__, он берется как список имен модуля, которые должны быть импортированы, когда встречается from package import *. Разработчик пакета должен обновлять список, когда выпускается новая версия пакета. Разработчики пакета могут также решить не поддерживать это, если они не видят использования для импортирования * из их пакета. Например, файл sound/effects/__init__.py может содержать следующий код:

__all__ = [ "echo", "surround", "reverse" ]

Это бы означало, что from sound.effects import * будет импортировать три названных подмодуля пакета sound.

Если __all__ не определена, выражение from sound.effects import * не импортирует все подмодули из пакета sound.effects в текущее пространство имен; это только обеспечивает то, что пакет sound.effects был импортирован (возможно выполняется какой-нибудь код инициализации из __init__.py) и затем импортирует любые имена, определенные в пакете. Это включает какие-либо имена определенные (и подмодули, загруженные явно) __init__.py. Это также включает какие-либо подмодули пакета, которые были явно загружены предыдущими операторами import. Рассмотрим этот код:

import sound.effects.echo import sound.effects.surround from sound.effects import *

В этом примере модули echo и surround импортируются в текущее пространство имен, потому что они определены в пакете sound.effects, когда выполняется выражение from...import (это также работает, когда определена __all__.)

Хотя некоторые модули разработаны для экспорта только имен, которые следуют определенным шаблонам, когда вы используете import *, это по-прежнему считается плохой практикой в рабочем коде.

Помните, нет ничего плохого в использовании from Package import specific_submodule! На самом деле это рекомендованная нотация, если не требуется из импортируемого модуля использовать подмодули с одинаковыми именами из различных пакетов.

Внутрипакетные ссылки.

Когда пакеты структурированы в подпакеты (как в пакете sound в примере), вы можете использовать абсолютные импорты для обращения к подмодулям сестринских пакетов. Например, если модулю sound.filters.vocoder надо использовать модуль echo в пакете sound.effects, он может использовать from sound.effects import echo.

Вы также можете писать относительные импорты, с формой оператора import from module import name. Такие импорты используют лидирующие точки для указания текущего и родительского пакетов, вовлеченных в относительный импорт. Например, из модуля surround вы можете использовать:

from. import echo from.. import formats from..filters import equalizer

Заметьте, такой относительный импорт основывается на имени текущего модуля. Поскольку имя главного модуля всегда "__main__", модули, предназначенные для использования в качестве главного модуля приложений Python, должны всегда использовать абсолютные импорты.



Поделиться:


Последнее изменение этой страницы: 2021-07-18; просмотров: 59; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.117.196.217 (0.026 с.)