Модули
Если выйти из интерпретатора Python и запустить его снова, сделанные вами определения (функции и переменные) будут потеряны. Поэтому, если вы хотите написать достаточно длинную программу, лучше подготовить входные данные для интерпретатора с помощью текстового редактора и запустить его, передав этот файл в качестве входных данных. Это называется созданием скрипта. По мере увеличения программы может понадобиться разбить её на несколько файлов, чтобы упростить сопровождение. Возможно, вам также захочется использовать удобную функцию, написанную для нескольких программ, не копируя её определение в каждую из них.
Для этого в Python можно помещать определения в файл и использовать их в скрипте или в интерактивном сеансе интерпретатора. Такой файл называется модулем; определения из модуля можно импортировать в другие модули или в модуль main (набор переменных, доступных в скрипте, выполняемом на верхнем уровне, и в режиме калькулятора).
Модуль — это файл, содержащий определения и инструкции 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, не добавляются непосредственно в текущее пространство имён (подробности см. в разделе Области видимости и пространства имён в Python); туда добавляется только имя модуля 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).
Подробнее см. раздел Инициализация пути поиска модулей sys.path.
Примечание
В файловых системах, поддерживающих символические ссылки, каталог, содержащий входной скрипт, определяется после перехода по символической ссылке. Иными словами, каталог, содержащий символическую ссылку, не добавляется в путь поиска модулей.
После инициализации программы 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 *? В идеале можно было бы ожидать, что Python обратится к файловой системе, определит, какие подмодули есть в пакете, и импортирует их все. Это может занять много времени, а импорт подмодулей может вызвать нежелательные побочные эффекты, которые должны возникать только при явном импорте подмодуля.
Единственное решение — предоставить явный список содержимого пакета. Инструкция import использует следующее соглашение: если код __init__.py пакета определяет список с именем __all__, он считается списком имён модулей, которые следует импортировать при встрече с from package import *. Автор пакета должен поддерживать этот список в актуальном состоянии при выпуске новой версии пакета. Автор также может отказаться от поддержки этой возможности, если не видит смысла в импорте * из своего пакета. Например, файл sound/effects/__init__.py может содержать следующий код:
__all__ = ["echo", "surround", "reverse"]
Это означает, что from sound.effects import * импортирует три указанных подмодуля пакета sound.effects.
Помните, что подмодули могут быть скрыты именами, определёнными локально. Например, если добавить функцию reverse в файл sound/effects/__init__.py, инструкция from sound.effects import * импортирует только два подмодуля — echo и surround, — но не подмодуль reverse, поскольку он скрыт локально определённой функцией reverse:
__all__ = [
"echo", # refers to the 'echo.py' file
"surround", # refers to the 'surround.py' file
"reverse", # !!! refers to the 'reverse' function now !!!
]
def reverse(msg: str): # <-- this name shadows the 'reverse.py' submodule
return msg[::-1] # in the case of a 'from sound.effects import *'
Если __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 импортируются в текущее пространство имён, поскольку в момент выполнения инструкции from...import они определены в пакете sound.effects. (Это также работает, если определён __all__.)
Хотя некоторые модули специально устроены так, чтобы при использовании import * экспортировать только имена, соответствующие определённым шаблонам, в рабочем коде такая практика всё равно считается плохой.
Помните: использовать from package import
specific_submodule совершенно нормально! Более того, это рекомендуемый вариант, если только импортирующему модулю не требуется использовать подмодули с одинаковыми именами из разных пакетов.
6.4.2. Ссылки внутри пакета
Если пакеты организованы в подпакеты (как пакет sound в примере), можно использовать абсолютный импорт для обращения к подмодулям соседних пакетов. Например, если модулю sound.filters.vocoder нужен модуль echo из пакета sound.effects, можно использовать from
sound.effects import echo.
Можно также использовать относительный импорт с формой инструкции импорта from module import name. В таких инструкциях начальные точки указывают на текущий и родительские пакеты, участвующие в относительном импорте. Например, из модуля surround можно использовать:
from . import echo from .. import formats from ..filters import equalizer
Обратите внимание: относительный импорт опирается на имя пакета текущего модуля. Поскольку у главного модуля нет пакета, модули, предназначенные для использования в качестве главного модуля приложения Python, должны всегда использовать абсолютный импорт.
6.4.3. Пакеты в нескольких каталогах
У пакетов есть ещё один специальный атрибут — __path__. Изначально ему присваивается последовательность строк с именами каталогов, содержащих файл __init__.py пакета; это происходит до выполнения кода в этом файле. Эту переменную можно изменить; это повлияет на последующий поиск модулей и подпакетов, содержащихся в пакете.
Хотя эта возможность нужна нечасто, с её помощью можно расширить набор модулей, найденных в пакете.
Сноски
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/tutorial/modules.html