ModuleNotFoundError: No module named в Python — как найти причину

опубликовано
обновлено
читать
≈ 10 мин
автор
среда и версия
CPython 3.14.5; раздел про pandas — Ubuntu 24.04 с Python 3.12.3, pip 24.0 и pandas 3.0.6
содержание решать задачи Python для начинающих

ModuleNotFoundError: No module named 'requests' означает, что импортёр Python не нашёл модуль requests. Это не всегда значит, что библиотека не установлена. Та же ошибка возникает, когда программа запущена другим интерпретатором, локальный пакет оказался вне sys.path, в имени есть опечатка или модуль отсутствует именно в этой версии Python.

Сначала прочитай имя в кавычках в последней строке traceback. Затем проверь интерпретатор и поиск модуля. Устанавливать пакет стоит, только когда знаешь его настоящее имя и видишь, что он нужен проекту. Если в кавычках pandas, переходи сразу к разделу No module named ‘pandas’. Примеры ниже проверены на CPython 3.14.5.

Python / 01

Пакет ищет тот Python, который запущен

Пакет ищет тот Python, который запущен01 Узнай интерпретатор sys.executable Установка в другое окружение не меняет этот процесс. 02 Проверь имя импорта find_spec("PIL") PIL — модуль, Pillow — имя устанавливаемого пакета. 03 Если пакет не установлен python -m pip install Pillow Если spec найден, проверь путь и точное имя из ошибки; переустановка может не помочь.01Узнай интерпретаторsys.executableУстановка в другое окружение не меняет этот процесс.02Проверь имя импортаfind_spec("PIL")PIL — модуль, Pillow — имя устанавливаемого пакета.03Если пакет неустановленpython -m pip install PillowЕсли spec найден, проверь путь и точное имя из ошибки; переустановка может не помочь.
Диагностика идёт от факта к причине: точное имя, тот же интерпретатор, затем результат поиска. Установка — только одна из возможных веток.

Сначала прочитай точное имя модуля

Важна последняя строка, а не только первый импорт в твоём файле:

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import report_tool
  File "/project/report_tool.py", line 3, in <module>
    import openpyxl
ModuleNotFoundError: No module named 'openpyxl'

Программа нашла report_tool, открыла его и остановилась на внутреннем импорте openpyxl. Проверять нужно openpyxl. Если сообщение содержит No module named 'app.settings', Python не нашёл подмодуль settings внутри app; установка пакета с именем app.settings здесь не следует из ошибки.

Не путай эту ошибку с ImportError: cannot import name. Во втором случае модуль найден, но в нём нет запрошенного имени: причина обычно в версии API, циклическом импорте или неверном имени объекта, а не в отсутствующей установке.

No module named ‘pandas’

Самый частый случай этой ошибки. pandas нет в стандартной библиотеке: его ставят отдельно, и ставить нужно в тот Python, которым запускаешь программу. Имя на PyPI и имя в import здесь совпадают, поэтому пакет называется просто pandas:

python -m pip install pandas

В Windows то же самое делают через лаунчер Python: py -3 -m pip install pandas.

Ubuntu и Debian: externally-managed-environment. В Ubuntu 24.04 и Debian 12 системный Python не даёт ставить в себя пакеты через pip:

$ pip install pandas
error: externally-managed-environment

× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

Это не поломка, а защита по PEP 668: от системного Python зависят программы самой ОС. Создай для проекта виртуальное окружение и поставь pandas туда:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install pandas
python -c "import pandas; print(pandas.__version__)"
3.0.6

После activate команда python запускает Python из .venv — им и запускай программу. Как устроено окружение, разобрано в инструкции по venv. Сообщение pip предлагает и другие пути: пакет дистрибутива sudo apt install python3-pandas — но в Ubuntu 24.04 это pandas 2.1.4, а не 3.0 — и флаг --break-system-packages, который ставит пакет прямо в системный Python. Второй лучше не трогать.

Jupyter Notebook. Тетрадка выполняет код в своём ядре, а pip из терминала может поставить пакет в другой Python. Ставь из самой тетрадки:

%pip install pandas

Магическая команда %pip запускает pip того интерпретатора, на котором работает ядро, и напоминает: Note: you may need to restart the kernel to use updated packages. Если pandas уже импортировали в этой тетрадке, перезапусти ядро.

PyCharm и VS Code. Если pandas установлен, а редактор показывает ту же ошибку, он запускает программу другим интерпретатором. Сверь пути, как в следующем разделе, и выбери в редакторе Python из той .venv, куда ставил пакет.

Без установки. Если нужно просто открыть таблицу и посчитать, в песочнице Python pandas скачивается сам при первом import pandas, как и numpy и matplotlib: ставить ничего не надо, всё работает в браузере. Как читать CSV и выбирать строки — в разборе «pandas DataFrame».

Проверь, какой Python запускает программу

Так бывает, когда пакет установлен в системный Python, а редактор или терминал запускает Python из другой .venv. Узнай путь к интерпретатору той же командой, которой запускаешь проект:

python -c "import sys; print(sys.executable)"
python -m pip --version

Первая команда печатает исполняемый файл Python. Вторая показывает путь к pip и версию Python, к которой он относится. Оба пути должны вести в одно окружение. Например:

/project/.venv/bin/python
pip 25.1.1 from /project/.venv/lib/python3.14/site-packages/pip (python 3.14)

Теперь проверь известное имя устанавливаемого дистрибутива:

python -m pip show Pillow

Location в выводе должен принадлежать той же .venv. Если pip show пишет Package(s) not found, это доказывает только одно: дистрибутив с таким именем не установлен для выбранного Python. Команда ничего не говорит о похожих именах и не подтверждает, что выбран правильный пакет.

Используй python -m pip, а не отдельную команду pip: модуль pip тогда запускает именно тот python, который стоит слева. Создание и активация окружения разобраны в инструкции по venv. Если проект управляет зависимостями через uv, запускай его по сценарию с uv add и uv run, не смешивая два окружения.

Проверь модуль без запуска приложения

importlib.util.find_spec() показывает, сможет ли текущий интерпретатор найти модуль:

python -c "import importlib.util; print(importlib.util.find_spec('PIL'))"

Для найденного модуля команда вернёт ModuleSpec с путём, например:

ModuleSpec(name='PIL', loader=..., origin='/project/.venv/lib/python3.14/site-packages/PIL/__init__.py', ...)

None означает, что обычный механизм импорта не видит PIL в этом окружении. Для верхнеуровневого имени такая проверка не выполняет код самого модуля, поэтому удобна до пробного импорта. После успешного find_spec узнай, какой файл загрузился на самом деле:

python -c "import PIL; print(PIL.__file__)"

Путь может обнаружить другую проблему: например, локальный PIL.py затенил установленную библиотеку. Переименуй такой файл и повтори проверку.

Имя на PyPI может не совпадать с именем в import

В import PIL указано имя импортируемого пакета. В python -m pip install Pillow указано имя дистрибутива. PyPA приводит эту пару как официальный пример несовпадения. Другой дистрибутив может экспортировать несколько импортируемых пакетов, а одно импортируемое имя могут предоставлять разные дистрибутивы.

Поэтому не подставляй текст ошибки в pip install автоматически. Пакет с совпадающим именем на PyPI может оказаться чужим, заброшенным или вредоносным. Найди имя зависимости в pyproject.toml, requirements.txt или документации проекта; для сторонней библиотеки проверь официальный сайт, репозиторий и страницу издателя на PyPI. Если источник зависимости неизвестен, остановись и уточни его, а не перебирай похожие пакеты.

Когда зависимость подтверждена, восстанови окружение из файла проекта:

python -m pip install -r requirements.txt

Для проекта с pyproject.toml, который устанавливается как пакет, команда может быть такой:

python -m pip install -e .

Режим -e полезен в разработке: пакет остаётся связан с исходниками. Не применяй эти команды наугад — выбери ту, которую предусматривает сам проект.

Локальный пакет: рабочая директория и package root

Допустим, проект устроен так:

shop-project/
├── pyproject.toml
└── shop_app/
    ├── __init__.py
    ├── cli.py
    └── prices.py

В cli.py используется абсолютный импорт:

from shop_app.prices import load_prices

Запускай модуль из корня shop-project, то есть из каталога, который содержит пакет shop_app:

cd shop-project
python -m shop_app.cli

Прямой запуск python shop_app/cli.py меняет начальную точку поиска: первой становится директория shop_app, а её родительский каталог может не попасть туда, где ожидается package root. Запуск через -m сохраняет пакетный контекст и позволяет абсолютному импорту найти shop_app.

Проверь текущую директорию и весь путь поиска одной командой:

python -c "import os, sys; print('cwd:', os.getcwd()); print(*sys.path, sep='\n')"

Python формирует sys.path при старте. Для файла в начале обычно стоит каталог этого файла, а для python -m, python -c и интерактивного запуска — текущая директория. Затем добавляются пути стандартной библиотеки, окружения и site-packages. Если каталог над shop_app отсутствует, исправь команду запуска, установи проект в окружение или перейди в package root.

Почему не стоит дописывать sys.path в коде

Такой фрагмент часто скрывает ошибку запуска:

import sys

sys.path.insert(0, '/home/user/shop-project')

Жёсткий путь работает только на одной машине. Относительный путь зависит от текущей директории, меняет приоритет модулей и может незаметно подхватить одноимённый файл не из того места. В тестах, редакторе и продакшене список путей снова различится.

Постоянный фикс — корректная структура пакета и одна воспроизводимая команда запуска: python -m shop_app.cli, python -m pip install -e . либо установка зависимостей проекта в его .venv. Ручное изменение sys.path оправдано в редких загрузчиках и одноразовой диагностике, но не как обычная настройка приложения.

Проверь опечатку, регистр и версию Python

Импортируемые имена чувствительны к регистру. import Requests и import requests — разные имена; на файловой системе без учёта регистра ошибка может временно не проявиться и сломать запуск на Linux. Сверь каждую часть имени с документацией и именем файла: user_profile.py импортируется как user_profile, а не user-profile.

Модуль стандартной библиотеки тоже зависит от версии Python. Например, tomllib появился в Python 3.11, а несколько устаревших модулей, включая imghdr, удалены в Python 3.13. Проверь фактическую версию и официальный индекс модулей для неё:

python --version
python -c "import importlib.util; print(importlib.util.find_spec('tomllib'))"

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

Симптом, проверка и исправление

СимптомЧто проверитьЧто исправить
pip install pandas отвечает externally-managed-environmentЭто системный Python Ubuntu или DebianСоздать .venv и ставить pandas туда
В терминале pandas импортируется, а в Jupyter — нетPython ядра тетрадкиВыполнить %pip install pandas в самой тетрадке
No module named 'requests', хотя установка уже былаsys.executable, python -m pip --versionВыбрать одну .venv и запускать pip через тот же Python
python -m pip show Pillow находит пакет, а import PIL падаетfind_spec('PIL'), поле LocationУбрать смешение окружений или восстановить установку по файлу зависимостей
Имя после No module named не совпадает с первым импортомПоследние строки tracebackИсправить или установить именно вложенную зависимость, подтверждённую проектом
Имя из import не находится на PyPI или выглядит подозрительноpyproject.toml, документацию и официальный репозиторийНайти настоящее имя дистрибутива; не ставить пакет по догадке
Локальный пакет находится в репозитории, но не импортируетсяcwd, sys.path, каталог над пакетомЗапустить из package root через python -m или установить проект с -e .
Ошибка появляется только на Linux или в CIРегистр букв в импорте и имени файлаПривести написание к точному имени модуля
Стандартный модуль есть в документации, но не в окруженииpython --version, индекс модулей этой версииИспользовать совместимую версию Python или документированную замену
find_spec показывает неожиданный файл проектаИмя локального .py-файлаПереименовать файл, который затеняет нужный пакет

Короткий порядок диагностики

  1. Прочитай точное имя после No module named и последний импорт в traceback.
  2. Сравни sys.executable с путём из python -m pip --version.
  3. Для подтверждённого дистрибутива выполни python -m pip show <имя>.
  4. Проверь импортируемое имя через importlib.util.find_spec().
  5. Для локального пакета проверь cwd, sys.path, package root и запуск через python -m.
  6. Только после этого устанавливай объявленную зависимость или исправляй структуру проекта.

Если программа после исправления импорта падает уже внутри try, обработку таких сбоев стоит строить через конкретные исключения. Базовые схемы собраны в статье «try/except в Python».

Не нашёл свою ошибку в разборе? Вставь трейсбек в расшифровщик ошибок Python: он переведёт сообщение, назовёт причину и покажет починку.

Источники