Когда Python встречает оператор import
, он начинает поиск указанного модуля или пакета в определенной последовательности мест, которые можно рассматривать как иерархию поиска.
Вот основные шаги и компоненты этой иерархии:
sys.modules
: Это кеш уже импортированных модулей. Python сначала проверяет здесь, чтобы избежать повторного импорта одного и того же модуля. Если модуль найден в sys.modules
, Python просто возвращает ссылку на существующий объект модуля, не выполняя никаких действий по его загрузке с диска.sys.path
: Это список строк, указывающих каталоги для поиска модулей. Он инициализируется из нескольких мест:
PYTHONPATH
.sys.path
: Python последовательно перебирает каждый каталог в sys.path
. Для обычных модулей (файлы .py
), Python ищет файл с именем, соответствующим импортируемому модулю и расширением .py
. Для пакетов (каталоги, содержащие файл __init__.py
), Python ищет каталог с именем пакета.__init__.py
), он выполняет файл __init__.py
. Этот файл может содержать код инициализации пакета, а также определять подмодули, экспортируемые пакетом. Он также может быть пустым. Существование __init__.py
говорит Python, что данный каталог следует рассматривать как пакет.__init__.py
(хотя могут его иметь). Механизм поиска для namespace packages отличается от обычных пакетов.from . import submodule
или from .. import parentmodule
). Точка (.
) обозначает текущий пакет, а две точки (..
) обозначают родительский пакет. Относительные импорты разрешаются относительно текущего местоположения модуля внутри иерархии пакетов.sys.modules
. Это позволяет избежать повторного поиска и загрузки модуля при последующих импортах.Пример:
Предположим, у вас есть следующая структура директорий:
my_project/
├── my_package/
│ ├── __init__.py
│ ├── module_a.py
│ └── submodule/
│ ├── __init__.py
│ └── module_b.py
└── main.py
И вы хотите импортировать module_b
в main.py
:
В main.py
:
from my_package.submodule import module_b
Python сначала проверит sys.modules
, затем sys.path
. Он найдет my_package
в sys.path
(если my_project
находится в sys.path
, или если main.py
запускается из my_project
). Затем он загрузит и выполнит my_package/__init__.py
и my_package/submodule/__init__.py
, прежде чем загрузить и выполнить my_package/submodule/module_b.py
.
Важно помнить:
sys.path
можно модифицировать во время выполнения для добавления дополнительных путей поиска модулей.