Модули
Если вы выйдете из интерпретатора 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, интерпретатор сначала ищет встроенный модуль с этим именем. Если не найдено, он затем ищет файл с именем spam.py в списке каталогов, заданном переменной sys.path. sys.path инициализируется из этих мест:
- Каталог, содержащий входной скрипт (или текущий каталог, когда файл не указан).
-
PYTHONPATH(список имён каталогов, с тем же синтаксисом, что и у переменной оболочки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) ['__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:
>>> 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.
Если __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 перед выполнением кода в этом файле. Это переменную можно изменить; при этом меняется будущий поиск модулей и подпакетов, содержащихся в пакете.
Хотя эта возможность не часто используется, она может быть использована для расширения набора модулей, найденных в пакете.
Примечания
-
1 -
На самом деле определения функций также являются «операторами», которые «выполняются»; выполнение определения функции на уровне модуля вносит имя функции в глобальную таблицу символов модуля.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/tutorial/modules.html