Модули
Если вы выйдете из интерпретатора 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 импортируются в текущее пространство имён, поскольку они определены в пакете 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.
Можно также использовать относительный импорт в форме инструкции импорта from module import name. В таком импорте начальные точки указывают на текущий и родительские пакеты, участвующие в относительном импорте. Например, из модуля surround можно использовать:
from . import echo from .. import formats from ..filters import equalizer
Обратите внимание, что относительный импорт основан на имени текущего модуля. Поскольку имя главного модуля всегда равно "__main__", модули, предназначенные для использования в качестве главного модуля приложения Python, всегда должны применять абсолютный импорт.
6.4.3. Пакеты в нескольких каталогах
У пакетов есть ещё один специальный атрибут — __path__. Перед выполнением кода из файла __init__.py он инициализируется как последовательность строк с именами каталогов, содержащих пакет. Эту переменную можно изменить; это повлияет на дальнейший поиск модулей и подмодулей, содержащихся в пакете.
Хотя эта возможность нужна нечасто, её можно использовать для расширения набора модулей, доступных в пакете.
Сноски
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/tutorial/modules.html