Импорт модулей в Python: на что смотреть новичку
Разбираемся, почему Python не видит ваш файл, чем import отличается from-import и как не поймать циклический импорт в первый же день.

Вы написали import mymodule, а Python отвечает ModuleNotFoundError: No module named 'mymodule' — хотя файл лежит рядом. Или наоборот: импорт сработал, но переменные оказались не теми, что вы ожидали. Импорт в Python выглядит как одна строка, но за ней стоит поиск по путям, кеширование модулей и порядок выполнения кода. Ниже — что реально ломается у новичка и как это чинить. Ориентируемся на Python 3.10 и новее, но почти всё справедливо и для более ранних 3.x.
Что происходит, когда вы пишете import
Когда интерпретатор встречает import mymodule, он делает три вещи по порядку. Сначала ищет модуль по списку путей sys.path. Найдя файл, выполняет его целиком сверху вниз — как обычный скрипт. Затем кладёт результат в словарь sys.modules, чтобы при повторном импорте не выполнять файл заново.
Отсюда два вывода, которые экономят часы отладки. Первый: код в импортируемом модуле выполняется в момент импорта, а не при первом обращении к функции. Если на верхнем уровне модуля стоит print("загрузка") или тяжёлый запрос к базе — он сработает сразу. Второй: повторный import того же модуля ничего не перезапускает, вы получаете уже загруженную копию из кеша.
Модуль выполняется один раз за жизнь процесса. Всё, что вы написали на верхнем уровне файла, — это не «объявления», а команды, которые выполнятся при первом импорте.
Где Python ищет модули: sys.path
Список путей поиска лежит в sys.path — это обычный список строк. Посмотреть его можно прямо из кода:
import sys
# Печатаем каждый путь на отдельной строке
for path in sys.path:
print(path)
В начале списка обычно стоит папка запущенного скрипта (или пустая строка, означающая текущую директорию), затем каталоги стандартной библиотеки и site-packages, куда pip ставит пакеты. Если вашего модуля нет ни в одном из этих мест — будет ModuleNotFoundError. Именно поэтому «файл лежит рядом» не всегда спасает: рядом с чем он лежит, зависит от того, откуда вы запустили Python, а не где физически находится файл.
import против from import
Три формы делают разное, и путаница между ними даёт неочевидные ошибки.
| Форма | Что попадает в ваше пространство имён | Как обращаться |
|---|---|---|
import math | Имя модуля math | math.sqrt(9) |
from math import sqrt | Только sqrt | sqrt(9) |
import math as m | Имя m | m.sqrt(9) |
from math import * | Всё «публичное» из модуля | sqrt(9), pi, ... |
Форма from module import * — главный источник «магии, которую не видно». Она тянет в текущий файл кучу имён, и вы уже не понимаете, откуда взялась переменная result: своя она или пришла из модуля. Хуже того, второй такой импорт может молча перезаписать имя из первого. В рабочем коде звёздочку почти никогда не используют — пишите явные имена.
Ещё одна ловушка: from mymodule import counter копирует значение имени на момент импорта. Если в mymodule потом переприсвоят counter, у вас останется старое значение. При import mymodule и обращении через mymodule.counter вы всегда видите актуальное.
Абсолютные и относительные импорты в пакете
Как только файлы складываются в папки, появляется вопрос пути. Пакет — это папка, которую Python рассматривает как модуль. В современном Python пакет обычно содержит файл __init__.py, пусть даже пустой.
Пусть структура такая:
myapp/
__init__.py
config.py
services/
__init__.py
billing.py
Из billing.py импортировать config.py можно двумя способами:
# Абсолютный импорт — от корня пакета
from myapp import config
# Относительный импорт — от текущего расположения
from .. import config
Абсолютный читается однозначно и не ломается при перемещении файла в другую папку внутри пакета. Относительный (с точками) короче, но работает только когда файл импортируется как часть пакета, а не запускается напрямую. Именно из-за этого новичок ловит ImportError: attempted relative import with no known parent package — об этом ниже.
Циклический импорт
Два модуля импортируют друг друга. a.py в начале пишет from b import foo, а b.py — from a import bar. При запуске Python начинает выполнять a, доходит до импорта b, переключается на b, там натыкается на импорт a — но a ещё не доисполнился, его имена не готовы. Результат — ImportError или AttributeError на пустом месте.
Три способа развязать цикл:
- Вынести общий код в третий модуль, от которого зависят оба, — самый чистый вариант.
- Импортировать не имя, а модуль целиком:
import bвместоfrom b import foo, и обращатьсяb.fooуже внутри функции, когда модуль точно загружен. - Перенести импорт внутрь функции, где он нужен, а не держать на верхнем уровне файла.
Если не получилось: типичные ошибки
Четыре сообщения, которые вы увидите чаще всего, и что за ними стоит.
ModuleNotFoundError: No module named 'X'— Python не нашёл модуль вsys.path. Проверьте, из какой папки запущен скрипт и установлен ли пакет в ту же среду, где работаете. Частая причина — пакет стоит в одном виртуальном окружении, а запуск идёт из другого.ImportError: cannot import name 'X' from 'Y'— модуль нашёлся, но имени в нём нет. Либо опечатка, либо циклический импорт, из-за которого имя ещё не создано на момент обращения.ImportError: attempted relative import with no known parent package— вы запустили файл с относительным импортом напрямую (python billing.py). Запускайте черезpython -m myapp.services.billingиз корня проекта, тогда Python знает родительский пакет.- Импортируется не тот файл — вы назвали свой скрипт как модуль стандартной библиотеки, например
random.pyилиemail.py. Ваш файл перекрывает настоящий. Переименуйте и удалите папку__pycache__рядом.
Если сомневаетесь, какой именно файл подтянулся, спросите об этом сам модуль:
import requests
# Печатает путь к файлу, который реально загружен
print(requests.__file__)
Виртуальное окружение решает половину проблем
Большинство мучений с «пакет установлен, но не импортируется» уходят, если каждый проект живёт в своём виртуальном окружении. Тогда pip install кладёт пакет туда же, откуда запускается Python:
# Создаём окружение в папке .venv (модуль venv входит в стандартную поставку)
python -m venv .venv
# Активируем: Linux/macOS
source .venv/bin/activate
# Активируем: Windows (PowerShell)
.venv\Scripts\Activate.ps1
После активации which python (или where python в Windows) должен показать путь внутри .venv. Ставьте пакеты и запускайте скрипты, не деактивируя окружение, — и половина импортных загадок исчезнет сама.
Что делать дальше
Заведите привычку запускать проект как пакет через python -m, а не файлами по отдельности — это делает импорты предсказуемыми. Когда дойдёте до __init__.py, посмотрите, как через него можно собрать «фасад» пакета: вынести часто используемые имена наверх, чтобы вместо from myapp.services.billing import charge писать from myapp import charge. И прочитайте раздел про систему импорта в официальной документации Python — там же описано, как работает механизм поиска и что можно настроить.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: The import system — Python documentation, venv — Creation of virtual environments
Частые вопросы
Почему пакет установлен через pip, но import его не находит?
Нужен ли файл __init__.py в каждой папке?
Чем import module лучше from module import name?
Что делать при ошибке attempted relative import with no known parent package?
У меня Python 3.8, всё из статьи сработает?
Как понять, какой именно файл подтянул import?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.