Представьте себе эту структуру каталогов:
app/
__init__.py
sub1/
__init__.py
mod1.py
sub2/
__init__.py
mod2.py
Я кодирую mod1
, и мне нужно импортировать что-то из mod2
. как мне это сделать?
Я пытался, from ..sub2 import mod2
но я получаю "Попытка относительного импорта в не-пакет".
Я погуглил, но нашел только " sys.path
манипулятивные" хаки. Разве нет чистого пути?
Изменить: все мои __init__.py
в настоящее время пустые
Edit2: я пытаюсь сделать это, потому что sub2 содержит классы, которые являются общими для подпакетов ( sub1
, subX
и т. Д.).
Edit3: поведение, которое я ищу, такое же, как описано в PEP 366 (спасибо Джон B)
Ответы:
Кажется, что каждый хочет сказать вам, что вы должны делать, а не просто отвечать на вопрос.
Проблема в том, что вы запускаете модуль как «__main__», передавая mod1.py в качестве аргумента интерпретатору.
От PEP 328 :
В Python 2.6 они добавляют возможность ссылаться на модули относительно основного модуля. PEP 366 описывает изменение.
Обновление : по словам Ника Коглана, рекомендуемая альтернатива - запустить модуль внутри пакета с помощью ключа -m.
источник
-m
переключатель, а не указав их имя файла напрямую.from sub2 import mod2
. Затем, чтобы запустить mod1, из приложения сделайтеpython -m sub1.mod1
.Вот решение, которое работает для меня:
Я делаю относительный импорт как,
from ..sub2 import mod2
а затем, если я хочу запустить,mod1.py
я иду в родительский каталогapp
и запускаю модуль, используя ключ python -m aspython -m app.sub1.mod1
.Реальная причина, по которой эта проблема возникает при относительном импорте, заключается в том, что относительный импорт работает, беря
__name__
свойство модуля. Если модуль запускается напрямую, то__name__
он установлен на__main__
и не содержит никакой информации о структуре пакета. И именно поэтому Python жалуется наrelative import in non-package
ошибку.Таким образом, с помощью ключа -m вы предоставляете информацию о структуре пакета в python, с помощью которой он может успешно разрешить относительный импорт.
Я сталкивался с этой проблемой много раз при выполнении относительного импорта. И, прочитав все предыдущие ответы, я все еще не мог понять, как решить это, чистым способом, без необходимости помещать шаблонный код во все файлы. (Хотя некоторые комментарии были действительно полезны, благодаря @ncoghlan и @XiongChiamiov)
Надеюсь, что это поможет кому-то, кто борется с проблемой относительного импорта, потому что проходить PEP на самом деле не весело.
источник
-m
было разработано для решения проблемы.from . import some_module
.python main.py
.main.py
делает:import app.package_a.module_a
module_a.py
делаетimport app.package_b.module_b
В качестве альтернативы 2 или 3 можно использовать:
from app.package_a import module_a
Это будет работать до тех пор, пока у вас есть
app
PYTHONPATH.main.py
может быть где угодноТаким образом, вы пишете
setup.py
для копирования (установки) всего пакета приложения и подпакетов в папки pythonmain.py
целевой системы и в папки сценариев целевой системы.источник
«Гвидо рассматривает выполнение сценариев внутри пакета как анти-шаблон» (отклонено PEP-3122 )
Я потратил так много времени, пытаясь найти решение, читая соответствующие посты здесь, в Stack Overflow и говоря себе: «Должен быть лучший способ!». Похоже, нет.
источник
-m
switch:python -m app.sub1.mod1
или вызватьapp.sub1.mod1.main()
из скрипта верхнего уровня (например, сгенерированного из точек входа setuptools, определенных в setup.py).Это решено на 100%:
Импортируйте настройки / local_setting.py в app / main.py:
main.py:
источник
sys.path.insert(0, "../settings")
а затемfrom local_settings import *
Я использую этот фрагмент для импорта модулей из путей, надеюсь, это поможет
источник
объяснение
nosklo's
ответа примерамипримечание: все
__init__.py
файлы пусты.Приложение / package_a / fun_a.py
Приложение / package_b / fun_b.py
main.py
если вы запустите
$ python main.py
это возвращает:from app.package_b import fun_b
from app.package_a.fun_a import print_a
поэтому файл в папке
package_b
используется файл в папкеpackage_a
, что вы хотите. Правильно??источник
К сожалению, это взлом sys.path, но он работает довольно хорошо.
Я столкнулся с этой проблемой в другом слое: у меня уже был модуль с указанным именем, но это был не тот модуль.
я хотел сделать следующее (модуль, из которого я работал, был module3):
Обратите внимание, что я уже установил mymodule, но в моей установке у меня нет "mymodule1"
и я получил бы ImportError, потому что он пытался импортировать из моих установленных модулей.
Я попытался сделать sys.path.append, и это не сработало. То, что сработало, было sys.path.insert
Так что вроде хак, но заставил все это работать! Так что имейте в виду, что если вы хотите, чтобы ваше решение переопределило другие пути, вам нужно использовать sys.path.insert (0, pathname), чтобы заставить его работать! Для меня это было очень неприятным камнем преткновения, многие говорят, что используют функцию «добавить» в sys.path, но это не работает, если у вас уже есть определенный модуль (я нахожу это очень странным поведением)
источник
sys.path.append('../')
отлично работает для меня (Python 3.5.2)Позвольте мне поставить это здесь для моей собственной справки. Я знаю, что это не очень хороший код Python, но мне нужен был скрипт для проекта, над которым я работал, и я хотел поместить скрипт в
scripts
каталог.источник
Как говорит @EvgeniSergeev в комментариях к ОП, вы можете импортировать код из
.py
файла в произвольном месте с помощью:Это взято из этого SO ответа .
источник
Взгляните на http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . Вы могли бы сделать
источник
Из документа Python ,
источник
Я обнаружил, что проще установить переменную окружения "PYTHONPATH" в верхнюю папку:
тогда:
Конечно, PYTHONPATH "глобальный", но это не доставило мне проблем.
источник
virtualenv
позволяет вам управлять вашими операциями импорта.Вдобавок к тому, что сказал Джон Б., похоже, что установка
__package__
переменной должна помочь, а не менять,__main__
что может испортить другие вещи. Но, насколько я мог проверить, он работает не совсем так, как должен.У меня та же проблема, и ни PEP 328, ни 366 не решают ее полностью, так как оба к концу дня нуждаются в том, чтобы глава пакета была включена в
sys.path
, насколько я понимаю.Я должен также упомянуть, что я не нашел, как отформатировать строку, которая должна идти в эти переменные. Это
"package_head.subfolder.module_name"
или что?источник
Вы должны добавить путь к модулю
PYTHONPATH
:источник
sys.path
, так какsys.path
инициализируется сPYTHONPATH
sys.path
необходимо жестко закодировать в исходном коде, в отличие от того,PYTHONPATH
который является переменной окружения и может быть экспортирован.