Python относительный импорт не работает

Как работают импорты в Python

Порой бывает трудно правильно реализовать import с первого раза, особенно если мы хотим добиться правильной работы на плохо совместимых между собой версиях Python 2 и Python 3. Попытаемся разобраться, что из себя представляют импорты в Python и как написать решение, которое подойдёт под обе версии языка.

Содержание

Ключевые моменты

  • Выражения 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 , становятся доступны импортирующему.

Читайте также:  У меня play market вообще не работает

Основы import и sys.path

Вот как оператор import производит поиск нужного модуля или пакета согласно документации Python:

При импорте модуля spam интерпретатор сначала ищёт встроенный модуль с таким именем. Если такого модуля нет, то идёт поиск файла spam.py в списке директорий, определённых в переменной sys.path . sys.path инициализируется из следующих мест:

  • директории, содержащей исходный скрипт (или текущей директории, если файл не указан);
  • директории по умолчанию, которая зависит от дистрибутива Python;
  • PYTHONPATH (список имён директорий; имеет синтаксис, аналогичный переменной окружения PATH ).

Программы могут изменять переменную sys.path после её инициализации. Директория, содержащая запускаемый скрипт, помещается в начало поиска перед путём к стандартной библиотеке. Это значит, что скрипты в этой директории будут импортированы вместо модулей с такими же именами в стандартной библиотеке.

Технически документация не совсем полна. Интерпретатор будет искать не только файл (модуль) 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 .

18–26 октября, Онлайн, Беcплатно

Кроме того, импорты в 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 добавляет информацию о запуске скриптов из командной строки. В частности, при запуске python

Источник

Относительный импорт в Python 3 не работает

У меня есть следующий каталог:

У меня есть функция f, определенная в файле file1.py.

Если в файле2.py я делаю

Я получаю следующую ошибку:

SystemError: родительский модуль » не загружен, не может выполнять относительные импорт

Почему? И как заставить его работать?

ОТВЕТЫ

Ответ 1

так как file1 и file2 находятся в одном каталоге, вам даже не нужно иметь файл __init__.py . Если вы собираетесь увеличивать масштаб, оставьте его там.

Чтобы импортировать что-то в файл в том же каталоге, просто сделайте это

from file1 import f

i.e, вам не нужно делать относительный путь .file1 , потому что они находятся в одном каталоге.

Если ваша основная функция, script или что-то еще, которое будет запускать все приложение, находится в другом каталоге, тогда вам нужно будет сделать все относительно того, где это выполняется.

Ответ 2

Запуск модулей внутри пакета в качестве исполняемых файлов является плохой практикой.

Когда вы разрабатываете что-то, вы либо создаете библиотеку, которая предназначена для импорта другими программами, и поэтому не имеет смысла разрешать непосредственное выполнение своих подмодулей или вы создаете исполняемый файл, и в этом случае нет оснований для сделайте его частью пакета.

Вот почему в setup.py вы различаете пакеты и скрипты. Пакеты будут находиться под site-packages , в то время как скрипты будут установлены под /usr/bin (или аналогичным расположением в зависимости от ОС).

Моя рекомендация, таким образом, должна использовать следующий макет:

Где file2.py импортирует file1.py как любой другой код, который хочет использовать библиотеку mydirectory , с абсолютным импортом:

Когда вы пишете setup.py script для проекта, вы просто перечисляете mydirectory как пакет и file2.py как script, и все будет работать. Не нужно возиться с sys.path .

Если вы когда-либо, по какой-то причине, действительно хотите запустить подмодуль пакета, правильный способ сделать это — использовать переключатель -m :

Загружает весь пакет, а затем выполняет модуль как script, позволяя относительному импорту добиться успеха.

Я бы лично избегал этого. Также потому, что многие люди даже не знают, что вы можете это сделать, и в итоге получите ту же ошибку, что и вы, и подумайте, что пакет сломан.

Относительно принятого в настоящее время ответа, в котором говорится, что вы должны использовать неявный относительный импорт from file1 import f , потому что он будет работать, поскольку они находятся в одном каталоге:

Это неверно!

    Он не будет работать в python3, где неявный относительный импорт будет запрещен и, безусловно, сломается, если вы установили модуль file1 (поскольку он будет импортирован вместо вашего модуля!).

Даже если он работает, file1 не будет рассматриваться как часть пакета mydirectory . Это может иметь значение.

Например, если file1 использует pickle , имя пакета важно для правильной загрузки/выгрузки данных.

Ответ 3

При запуске исходного файла python запрещается импортировать другой файл, находящийся в текущем пакете, используя относительный импорт.

Обратите внимание, что относительный импорт основан на имени текущего модуля. Поскольку имя основного модуля всегда «__main__», модули, предназначенные для использования в качестве основного модуля приложения Python, должны всегда использовать абсолютный импорт.

Итак, как сказал @mrKelley, вам нужно использовать абсолютный импорт в такой ситуации.

Ответ 4

Пример импорта из одного файла в другой

Импортируйте пример пакета в mainccript

Переменная sys.path представляет собой список строк, определяющих путь поиска интерпретаторов для модулей. Он инициализируется путём по умолчанию, взятым из переменной окружения PYTHONPATH или из встроенного значения по умолчанию, если PYTHONPATH не установлен. Вы можете изменить его, используя стандартные операции с списком:

Вставка его в начале имеет преимущество, гарантирующее, что поиск пути выполняется перед другими (даже встроенными) в случае конфликтов имен.

Источник

Почему не работает относительный import в Python (PyCharm)?

Есть следующая архитектура проекта:

Проблема заключается в неисправности относительного импорта. Т.е. в теории все должно работать, как надо, но что-то идет не так.

В файле main.py я пишу from . import sieves.py. Т.е. делаю относительный импорт. Так же в файле test_1.py я тоже импортирую этот файл и пишу from .. import sieves.py. PyCharm не ругается и не подчеркивает это, как ошибку, но при запуске я получаю это:

Это очень странно, ведь я указал рабочую директорию и даже проверил ее через os.getcwd(). Я видел такую же проблему на нашем всеми любимом портале, и там было решение указать именно рабочую директорию. Но мне это не помогло.

Заранее благодарю за ответы!

2 ответа 2

Я со всем разобрался! Оказывается, я не так понимал импорт в Python.

  1. Дело в том, что когда мы запускаем какой-либо файл, для Python нет ничего выше этого ЗАПУЩЕННОГО файла. Т.е. запущенный файл является корнем, и мы не сможем при импорте подняться выше него, даже если там будут какие-то другие модули/пакеты. Мы можем импортировать в ЗАПУЩЕННЫЙ файл (у которого __name__ == «__main__» ) только пакеты и модули, находящиеся на одном уровне с ним или ниже.
  2. __main__.py делает ПАКЕТ, в котором он лежит, ЗАПУСКАЕМЫМ. Поэтому у меня не работала команда python __main__.py . Нужно в таком случае использовать python -m package , где -m говорит, что надо запустить как модуль.
  3. Использовать main.py в самом корне каталога удобно тем, что у нас никогда ничего не будет выше этого файла. Значит, мы не запутаемся при импорте и всегда будем импортировать только то, что рядом с файлом и что ниже его по уровню. Еще раз: __main__.py лишь делает ПАКЕТ запускаемым.

Надеюсь, кому-то поможет 🙂

Попробуйте просто import sieves , интерпретатор по идее должен рассматировать директорию package как main директорию проекта, при наличии __main__ в ней

Всё ещё ищете ответ? Посмотрите другие вопросы с метками python pycharm или задайте свой вопрос.

Похожие

Подписаться на ленту

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.10.19.40496

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Источник

Проблема с импортом из текущей директории

Стараюсь изучить импорт модулей python . Но недавно столкнулся с проблемой при импорте модуля из текущей директории. Директория выглядит так:

В файле src.py хранятся данные, которые я собираюсь собирать оттуда в файле source.py . Я пишу:

В чём ошибка? Что я делаю не так?

2 ответа 2

Вкратце: замените from . import src на import src .

Импорт через точку — это относительный импорт. Относительный импорт работает только внутри пакетов, при этом такой импорт будет работать только если source.py импортирован из пакета, а не запущен или импортирован как отдельный модуль. К примеру, имеем такую структуру файлов:

Директория sources при этом является пакетом, несмотря на отсутствие файла __init__.py (начиная с Python 3.3 его наличие стало необязательным, см. PEP 420 — Implicit Namespace Packages).

  • В модуле module.py одна строка: from sources.source import *
  • В source.py одна строка: from . import src
  • В src.py : print(«Hello from src.py!»)

Запускаем: python3 module.py

Вывод: Hello from src.py!

Если перейти в sources и запустить python3 source.py , то будет такая ошибка:

Перевод — «попытка относительного импорта при неизвестном родительском пакете». Аналогичная ошибка будет, если попытаться импортировать source.py напрямую с помощью import source .

Таким образом, у вас два варианта:

  • вынести ваши файлы в пакет, тогда можно будет использовать относительный импорт (придется его использовать импорта для модулей в этом же пакете, т.е. импорт вида import src или from src import . из модуля того же пакета работать не будет)
  • либо не выносить в пакет, и использовать обычный абсолютный импорт.

Источник

Относительно импорта в Python 3 не работает

у меня есть следующий каталог:

у меня есть функция f, определенная в file1.py.

Если, в file2.py-я делаю

Я получаю следующую ошибку:

SystemError: Родительский модуль » не загружен, не может выполнять относительные импорт

почему? И как заставить его работать?

4 ответов

С file1 и file2 находятся в одном каталоге, вам даже не нужно иметь . Если вы собираетесь наращивать, то оставьте его там.

импортировать что-то в файл в том же каталоге, просто сделать такой

from file1 import f

т. е. вам не нужно делать относительный путь .file1 потому что они находятся в той же директории.

если ваша основная функция, скрипт или что-то еще, это будет работать все приложение в другом каталоге вам придется сделать все относительно того, где это выполняется.

запуск модулей внутри пакета в качестве исполняемых файлов-это плохая практика.

когда вы разрабатываете что-то, вы либо создаете библиотеку, которая предназначена для импорта другими программами, и поэтому нет смысла разрешать выполнение ее подмодулей напрямую, либо создаете исполняемый файл, и в этом случае нет причин делать его частью пакета.

именно поэтому setup.py вы различаете пакеты и скрипты. Пакеты идите под site-packages в то время как скрипты будут установлены под /usr/bin (или аналогичное местоположение в зависимости от ОС).

моя рекомендация, таким образом, использовать следующий макет:

здесь file2.py импорт file1.py как и любой другой код, который хочет использовать библиотеку mydirectory С абсолютное импорт:

когда вы пишите setup.py скрипт для проекта вы просто перечисляете mydirectory в пакет и file2.py как сценарий и все будет работать. Нет необходимости возиться с sys.path .

если вы когда-либо по какой-то причине действительно хотите запустить подмодуль пакета, правильный способ сделать это-использовать -m переключатель:

это загружает весь пакет, а затем выполняет модуль как скрипт, позволяя относительному импорту успешно.

лично я бы этого не делал. Также потому, что многие люди даже не знают, что вы можете это сделать и в конечном итоге получите такая же ошибка, как и вы, и думаете, что пакет сломан.

относительно принятого в настоящее время ответа, в котором говорится, что вы должны просто использовать подразумевается относительный импорт from file1 import f , потому что он будет работать, так как они находятся в той же директории:

это неправильно!

    это не работа в python3, где неявный относительный импорт запрещен и, безусловно, сломается, если у вас есть установлена file1 модуль (так как он будет импортирован вместо вашего модуля!).

даже если он работает в file1 не будет рассматриваться как часть . Это can вопрос.

например, если file1 использует pickle , имя пакета важно для правильной загрузки / выгрузки данных.

при запуске исходного файла python запрещено импортировать другой файл, который находится в текущем пакете, используя относительный импорт.

обратите внимание, что относительный импорт основан на имени текущего модуля. Поскольку имя основного модуля всегда » _ _ main__», модули, предназначенные для использования в качестве основного модуля приложения Python, всегда должны использовать абсолютный импорт.

Так, как @mrKelley сказал, вам нужно использовать абсолютный импорт в такой ситуации.

пример импорта из одного файла в другой

импортируйте пример пакета в mainscript

переменная sys.path-это список строк, определяющих путь поиска интерпретатора для модулей. Он инициализируется путем по умолчанию, взятым из переменной среды PYTHONPATH, или из встроенного значения по умолчанию, если PYTHONPATH не установлен. Вы можете изменить его с помощью стандартных операций списка:

вставка его в начале имеет преимущество гарантировать, что путь ищется перед другими (даже встроенными) в случае конфликтов именования.

Источник

Оцените статью