Spec-Zone.ru › Python 3.11

Модули

Если выйти из интерпретатора 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, непосредственно в текущее пространство имён (см. Пространства имён и области видимости в 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 *? В идеале, хотелось бы, чтобы это как-то вышло в файловую систему, определило, какие подмодули присутствуют в пакете, и импортировало их все. Это может занять много времени, а импорт подмодулей может иметь нежелательные побочные эффекты, которые должны происходить только при явном импорте подмодуля.

Единственное решение — для автора пакета предоставить явный индекс пакета. Выражение import использует следующую конвенцию: если код пакета определяет список с именем __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 перед выполнением кода в этом файле. Эта переменная может быть изменена; это повлияет на будущие поиски модулей и подпакетов, содержащихся в пакете.

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

Примечания

1

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

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

Spec-Zone.ru

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