Как работают импорты в Python
Импорты не так просты, как кажется. Тем более если они пишутся для двух несовместимых версий языка. Разбираемся с основными проблемами и их решением.

Порой бывает трудно правильно реализовать import
с первого раза, особенно если мы хотим добиться правильной работы на плохо совместимых между собой версиях Python 2 и Python 3. Попытаемся разобраться, что из себя представляют импорты в Python и как написать решение, которое подойдёт под обе версии языка.
Содержание
- Ключевые моменты
- Основные определения
- Пример структуры директорий
- Что делает import
- Основы import и sys.path
- Чуть подробнее о sys.path
- Всё о __init__.py
- Использование объектов из импортированного модуля или пакета
- Используем dir() для исследования содержимого импортированного модуля
- Импортирование пакетов
- Абсолютный и относительный импорт
- Примеры
- Python 2 vs Python 3
- Прочие темы, не рассмотренные здесь, но достойные упоминания
Ключевые моменты
- Выражения
import
производят поиск по списку путей вsys.path
. sys.path
всегда включает в себя путь скрипта, запущенного из командной строки, и не зависит от текущей рабочей директории.- Импортирование пакета по сути равноценно импортированию
__init__.py
этого пакета.
Основные определения
- Модуль: любой файл
*.py
. Имя модуля — имя этого файла. - Встроенный модуль: «модуль», который был написан на Си, скомпилирован и встроен в интерпретатор Python, и потому не имеет файла
*.py
. - Пакет: любая папка, которая содержит файл
__init__.py
. Имя пакета — имя папки.С версии Python 3.3 любая папка (даже без __init__.py) считается пакетом. - Объект: в Python почти всё является объектом — функции, классы, переменные и т. д.
Пример структуры директорий
Обратите внимание, что в корневой папке test/
нет файла __init__.py
.
Что делает import
При импорте модуля Python выполняет весь код в нём. При импорте пакета Python выполняет код в файле пакета __init__.py
, если такой имеется. Все объекты, определённые в модуле или __init__.py
, становятся доступны импортирующему.
Основы import и sys.path
Вот как оператор import
производит поиск нужного модуля или пакета согласно документации Python:
При импорте модуляspam
интерпретатор сначала ищёт встроенный модуль с таким именем. Если такого модуля нет, то идёт поиск файлаspam.py
в списке директорий, определённых в переменнойsys.path
.sys.path
инициализируется из следующих мест:t
Программы могут изменять переменную- директории, содержащей исходный скрипт (или текущей директории, если файл не указан);
t- директории по умолчанию, которая зависит от дистрибутива Python;
tPYTHONPATH
(список имён директорий; имеет синтаксис, аналогичный переменной окруженияPATH
).sys.path
после её инициализации. Директория, содержащая запускаемый скрипт, помещается в начало поиска перед путём к стандартной библиотеке. Это значит, что скрипты в этой директории будут импортированы вместо модулей с такими же именами в стандартной библиотеке.Источник: Python 2 и Python 3
Технически документация не совсем полна. Интерпретатор будет искать не только файл (модуль) spam.py
, но и папку (пакет) spam
.
Обратите внимание, что Python сначала производит поиск среди встроенных модулей — тех, которые встроены непосредственно в интерпретатор. Список встроенных модулей зависит от дистрибутива Python, а найти этот список можно в sys.builtin_module_names
(Python 2 и Python 3). Обычно в дистрибутивах есть модули sys
(всегда включён в дистрибутив), math
, itertools
, time
и прочие.
В отличие от встроенных модулей, которые при поиске проверяются первыми, остальные (не встроенные) модули стандартной библиотеки проверяются после директории запущенного скрипта. Это приводит к сбивающему с толку поведению: возможно «заменить» некоторые, но не все модули стандартной библиотеки. Допустим, модуль math
является встроенным модулем, а random
— нет. Таким образом, import math
в start.py
импортирует модуль из стандартной библиотеки, а не наш файл math.py
из той же директории. В то же время, import random
в start.py
импортирует наш файл random.py
.
Кроме того, импорты в Python регистрозависимы: import Spam
и import spam
— разные вещи.
Функцию pkgutil.iter_modules()
(Python 2 и Python 3) можно использовать, чтобы получить список всех модулей, которые можно импортировать из заданного пути:
Чуть подробнее о sys.path
Чтобы увидеть содержимое sys.path
, запустите этот код:
Документация Python описывает sys.path
так:
Список строк, указывающих пути для поиска модулей. Инициализируется из переменной окруженияPYTHONPATH
и директории по умолчанию, которая зависит от дистрибутива Python.При запуске программы после инициализации первым элементом этого списка,path[0]
, будет директория, содержащая скрипт, который был использован для вызова интерпретатора Python. Если директория скрипта недоступна (например, если интерпретатор был вызван в интерактивном режиме или скрипт считывается из стандартного ввода), тоpath[0]
является пустой строкой. Из-за этого Python сначала ищет модули в текущей директории. Обратите внимание, что директория скрипта вставляется перед путями, взятыми изPYTHONPATH
.Источник: Python 2 и Python 3
Документация к интерфейсу командной строки Python добавляет информацию о запуске скриптов из командной строки. В частности, при запуске python <script>.py
.
Если имя скрипта ссылается непосредственно на Python-файл, то директория, содержащая этот файл, добавляется в началоsys.path
, а файл выполняется как модульmain
.Источник: Python 2 и Python 3
Итак, повторим порядок, согласно которому Python ищет импортируемые модули:
- Модули стандартной библиотеки (например,
math
,os
). - Модули или пакеты, указанные в
sys.path
:Если интерпретатор Python запущен в интерактивном режиме:sys.path[0] — пустая строка ''. Это значит, что Python будет искать в текущей рабочей директории, из которой вы запустили интерпретатор. В Unix-системах эту директорию можно узнать с помощью команды pwd.Если мы запускаем скрипт командой python