Spec-Zone.ru › Python 3.9

Модули

Если вы выйдете из интерпретатора Python и снова его запустите, все созданные вами определения (функции и переменные) будут потеряны. Поэтому, если вы хотите написать программу побольше, лучше использовать текстовый редактор для подготовки входных данных для интерпретатора и запускать её с этим файлом в качестве входных данных. Это называется созданием скрипта. По мере увеличения размера программы, вы можете захотеть разбить её на несколько файлов для лучшей поддержки. Возможно, вы захотите использовать полезную функцию, которую написали в нескольких программах, не копируя её определение в каждую программу.

Для поддержки этого, в Python есть способ поместить определения в файл и использовать их в скрипте или в интерактивной сессии интерпретатора. Такой файл называется модулем; определения из модуля могут быть импортированы в другие модули или в главный модуль (совокупность переменных, к которым у вас есть доступ в скрипте, выполняемом на верхнем уровне, и в режиме калькулятора).

Модуль — это файл, содержащий определения и операторы Python. Имя файла — это имя модуля с добавлением суффикса .py. Внутри модуля имя модуля (как строка) доступно в качестве значения глобальной переменной __name__. Например, воспользуйтесь вашим любимым текстовым редактором, чтобы создать файл под названием fibo.py в текущей директории со следующим содержимым:

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

Теперь запустите интерпретатор Python и импортируйте этот модуль с помощью следующей команды:

>>> import fibo

Это не помещает имена определённых в fibo функций непосредственно в текущую таблицу символов; оно только помещает имя модуля fibo туда. Используя имя модуля, вы можете получить доступ к функциям:

>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'

Если вы часто используете функцию, вы можете назначить её локальному имени:

>>> fib = fibo.fib
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

6.1. Подробнее о модулях

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

Каждый модуль имеет свою собственную частную таблицу символов, которая используется в качестве глобальной таблицы символов для всех функций, определённых в модуле. Таким образом, автор модуля может использовать глобальные переменные в модуле, не беспокоясь о случайных столкновениях с глобальными переменными пользователя. С другой стороны, если вы знаете, что делаете, вы можете обратиться к глобальным переменным модуля с помощью той же нотации, которая используется для обращения к его функциям, modname.itemname.

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

Существует вариант оператора import, который импортирует имена из модуля непосредственно в таблицу символов импортирующего модуля. Например:

>>> from fibo import fib, fib2
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

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

Существует даже вариант импорта всех имен, которые определяет модуль:

>>> from fibo import *
>>> fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Это импортирует все имена, кроме тех, которые начинаются с нижнего подчёркивания (_). В большинстве случаев программисты Python не используют эту возможность, так как она вводит неизвестный набор имён в интерпретатор, потенциально скрывая некоторые вещи, которые вы уже определили.

Обратите внимание, что, как правило, практика импорта * из модуля или пакета не приветствуется, поскольку это часто приводит к плохо читаемому коду. Однако её можно использовать для экономии набора текста в интерактивных сессиях.

Если за именем модуля следует as, то имя, следующее за as, напрямую привязывается к импортированному модулю.

>>> import fibo as fib
>>> fib.fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Это фактически импортирует модуль так же, как import fibo сделает, с единственным отличием, что он доступен как fib.

Его также можно использовать при использовании from с аналогичным эффектом:

>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

Примечание

Из соображений эффективности каждый модуль импортируется только один раз за сеанс работы с интерпретатором. Поэтому, если вы измените свои модули, вам необходимо перезапустить интерпретатор — или, если вы просто хотите протестировать один модуль интерактивно, используйте importlib.reload(), например, import importlib; importlib.reload(modulename).

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

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

python fibo.py <arguments>

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

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

вы можете сделать файл доступным как скриптом, так и импортируемым модулем, поскольку код, анализирующий командную строку, выполняется только в том случае, если модуль выполняется как «главный» файл:

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

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

>>> import fibo
>>>

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

6.1.2. Путь поиска модулей

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

  • Каталог, содержащий входной скрипт (или текущий каталог, когда файл не указан).
  • PYTHONPATH (список имён каталогов, с тем же синтаксисом, что и у переменной оболочки PATH).
  • Зависимые от установки значения по умолчанию (по традиции включая каталог site-packages, обрабатываемый модулем site).

Примечание

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

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

6.1.3. «Компилированные» файлы Python

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

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

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

Некоторые советы для экспертов:

  • Можно использовать переключатели -O или -OO в командной строке Python для уменьшения размера скомпилированного модуля. Переключатель -O удаляет операторы assert, переключатель -OO удаляет как операторы assert, так и строки __doc__. Поскольку некоторые программы могут полагаться на их наличие, вы должны использовать этот параметр только в том случае, если вы знаете, что делаете. «Оптимизированные» модули имеют метку opt- и, как правило, меньше. Будущие релизы могут изменить эффект оптимизации.
  • Программа не работает быстрее, когда она читается из файла .pyc по сравнению с чтением из файла .py; единственное, что быстрее в файлах .pyc — это скорость их загрузки.
  • Модуль compileall может создавать файлы .pyc для всех модулей в каталоге.
  • Более подробную информацию об этом процессе, включая блок-схему решений, см. в PEP 3147.

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

В 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, или из встроенного значения по умолчанию, если PYTHONPATH не задана. Вы можете изменить её, используя стандартные операции со списками:

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

6.3. Функция dir()

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

>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)  
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
 '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
 '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
 '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
 '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
 'breakpointhook', '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', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
 'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
 'stdin', 'stdout', 'thread_info', 'unraisablehook', '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:

>>> 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']

6.4. Пакеты

Пакеты — это способ структурирования пространства имён модулей Python с использованием «точечных имён модулей». Например, имя модуля A.B обозначает подмодуль с именем B в пакете с именем A. Так же как использование модулей избавляет авторов разных модулей от необходимости беспокоиться об именах глобальных переменных друг друга, использование точечных имён модулей избавляет авторов многомодульных пакетов, таких как NumPy или Pillow, от необходимости беспокоиться об именах модулей друг друга.

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

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for 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, элемент может быть либо подмодулем (или подпакетом) пакета, либо каким-то другим именем, определённым в пакете, например, функцией, классом или переменной. Инструкция import сначала проверяет, определён ли элемент в пакете; если нет, предполагается, что это модуль, и пытается загрузить его. Если его не удаётся найти, генерируется исключение ImportError.

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

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

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

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

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

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

Если __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 нет ничего плохого! На самом деле, это рекомендуемый способ, если импортирующему модулю не нужны подмодули с одинаковым именем из разных пакетов.

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

Когда пакеты структурированы в подпакеты (как с пакетом 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, должны всегда использовать абсолютные импорты.

6.4.3. Пакеты в нескольких каталогах

Пакеты поддерживают ещё один специальный атрибут, __path__. Он инициализируется списком, содержащим имя каталога, содержащего пакет __init__.py перед выполнением кода в этом файле. Эта переменная может быть изменена; это повлияет на будущие поиски модулей и подпакетов, содержащихся в пакете.

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

Примечания

1

На самом деле определения функций также являются «инструкциями», которые «выполняются»; выполнение определения функции на уровне модуля добавляет имя функции в глобальную таблицу символов модуля.

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/tutorial/modules.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API