как сделать относительный импорт в python?

<p>представьте себе эту структуру каталогов:</p><pre><code>app/ \_\_init\_\_.py sub1/ \_\_init\_\_.py mod1.py sub2/ \_\_init\_\_.py mod2.py </code></pre><p>я кодирую <code>mod1</code>, и мне нужно импортировать что-то из <code>mod2</code>. как я должен это делать?</p><p>я попытался <code>from ..sub2 import mod2</code>, но я получаю "попытка относительного импорта в не пакет".</p><p>я погуглил, но нашел только хаки "<code>sys.path</code> манипуляция". разве нет чистого пути?</p><hr><p>правка: все мои <code>\_\_init\_\_.py</code> в настоящее время пустые</p><p>edit2: я пытаюсь сделать это, потому что sub2 содержит классы, которые совместно используются субпакетами (<code>sub1</code>, <code>subx</code> и т.д.).</p><p>edit3: поведение, которое я ищу, такое же, как описано в <a href="http://www.python.org/dev/peps/pep-0366/">pep 366</a> (спасибо джон b)</p>

<p>кажется, что каждый хочет сказать вам, что вы должны делать, а не просто отвечать на вопрос.</p><p>проблема в том, что вы запускаете модуль как "\_\_main\_\_", передавая mod1.py в качестве аргумента интерпретатору.</p><p>от <a href="http://www.python.org/dev/peps/pep-0328/">пкп 328</a> :</p><blockquote> <p>относительный импорт использует атрибут модуля \_\_name\_\_, чтобы определить позицию этого модуля в иерархии пакетов. если имя модуля не содержит никакой информации о пакете (например, оно установлено на "\_\_main\_\_"), то относительный импорт разрешается так, как если бы модуль был модулем верхнего уровня, независимо от того, где модуль фактически расположен в файловой системе.</p> </blockquote><p>в python 2.6 они добавляют возможность ссылаться на модули относительно основного модуля. <a href="http://python.org/dev/peps/pep-0366/">pep 366</a> описывает изменение.</p><p><strong> обновление </strong>: по словам ника коглана, рекомендуемая альтернатива - запускать модуль внутри пакета с помощью ключа -m.</p>

<pre><code>main.py setup.py app/ -> \_\_init\_\_.py package\_a/ -> \_\_init\_\_.py module\_a.py package\_b/ -> \_\_init\_\_.py module\_b.py </code></pre><ol> <li>вы запускаете <code>python main.py</code>.</li> <li><code>main.py</code> делает: <code>import app.package\_a.module\_a</code></li> <li><code>module\_a.py</code> делает <code>import app.package\_b.module\_b</code></li> </ol><p>в качестве альтернативы 2 или 3 можно использовать: <code>from app.package\_a import module\_a</code></p><p>это будет работать до тех пор, пока у вас есть <code>app</code> в вашей pythonpath. тогда <code>main.py</code> может быть где угодно.</p><p>таким образом, вы пишете <code>setup.py</code> для копирования (установки) всего пакета приложения и подпакетов в папки целевой системы python, а <code>main.py</code> в целевые папки сценариев системы.</p>

<p>вот решение, которое работает для меня:</p><p>я делаю относительный импорт как <code>from ..sub2 import mod2</code>, а затем, если я хочу запустить <code>mod1.py</code>, тогда я иду в родительский каталог <code>app</code> и запускаю модуль с помощью переключателя python -m как <code>python -m app.sub1.mod1</code>.</p><p>настоящая причина, по которой эта проблема возникает при относительном импорте, заключается в том, что относительный импорт работает, принимая свойство <code>\_\_name\_\_</code> модуля. если модуль запускается напрямую, то <code>\_\_name\_\_</code> имеет значение <code>\_\_main\_\_</code> и не содержит никакой информации о структуре пакета. и именно поэтому python жалуется на ошибку <code>relative import in non-package</code>.</p><p>таким образом, с помощью ключа -m вы предоставляете информацию о структуре пакета в python, с помощью которой он может успешно разрешить относительный импорт.</p><p>я сталкивался с этой проблемой много раз при выполнении относительного импорта. и, прочитав все предыдущие ответы, я все еще не мог понять, как решить это, чистым способом, без необходимости помещать шаблонный код во все файлы. (хотя некоторые комментарии были действительно полезны, благодаря @ncoghlan и @xiongchiamiov)</p><p>надеюсь, что это помогает кому-то, кто борется с проблемой относительного импорта, потому что проходить через pep не очень весело.</p>

<p>"гвидо рассматривает выполнение сценариев внутри пакета как анти-шаблон" (отклонено <a href="http://www.python.org/dev/peps/pep-3122/">pep-3122</a> )</p><p>я потратил так много времени, пытаясь найти решение, читая соответствующие посты здесь, на stack overflow и говоря себе: "должен быть лучший способ!". похоже, нет.</p>

<p>это решено на 100%:</p><ul> <li>приложение/ <ul> <li>main.py</li> </ul> </li> <li>настройки / <ul> <li>local\_setings.py</li> </ul> </li> </ul><p>импортируйте настройки/local\_setting.py в app/main.py:</p><p>main.py:</p><pre><code>import sys sys.path.insert(0, "../settings") try: from local\_settings import * except importerror: print('no import') </code></pre>

<pre><code>def import\_path(fullpath): """ import a file with full path specification. allows one to import from anywhere, something \_\_import\_\_ does not do. """ path, filename = os.path.split(fullpath) filename, ext = os.path.splitext(filename) sys.path.append(path) module = \_\_import\_\_(filename) reload(module) # might be out of date del sys.path[-1] return module </code></pre><p>я использую этот фрагмент для импорта модулей из путей, надеюсь, это поможет</p>

<p>объяснение <code>nosklo's</code> ответа с примерами</p><p><em>примечание: все файлы <code>\_\_init\_\_.py</code> пусты.</em></p><pre><code>main.py app/ -> \_\_init\_\_.py package\_a/ -> \_\_init\_\_.py fun\_a.py package\_b/ -> \_\_init\_\_.py fun\_b.py </code></pre><h3>приложение/package\_a/fun\_a.py</h3><pre><code>def print\_a(): print 'this is a function in dir package\_a' </code></pre><h3>приложение/package\_b/fun\_b.py</h3><pre><code>from app.package\_a.fun\_a import print\_a def print\_b(): print 'this is a function in dir package\_b' print 'going to call a function in dir package\_a' print '-'*30 print\_a() </code></pre><h3>main.py</h3><pre><code>from app.package\_b import fun\_b fun\_b.print\_b() </code></pre><p>если вы запускаете <code>$ python main.py, он возвращает:this is a function in dir package_b going to call a function in dir package_a ------------------------------ this is a function in dir package_a  main.py делает: from app.package_b import fun_b fun_b.py делает from app.package_a.fun_a import print_a поэтому файл в папке package_b используется файл в папке package_a, который вам нужен. правильно??

к сожалению, это взлом sys.path, но он работает довольно хорошо.я столкнулся с этой проблемой в другом слое: у меня уже был модуль с указанным именем, но это был не тот модуль.я хотел сделать следующее (модуль, из которого я работал, был module3):mymodule __init__.py mymodule1 __init__.py mymodule1_1 mymodule2 __init__.py mymodule2_1 import mymodule.mymodule1.mymodule1_1 обратите внимание, что я уже установил mymodule, но в моей установке у меня нет "mymodule1"и я получил бы importerror, потому что он пытался импортировать из моих установленных модулей.я попытался сделать sys.path.append, и это не сработало. то, что сработало, было <strong>sys.path.insert</strong>if __== '__main__': sys.path.insert(0, '../..') так что вроде хак, но заставил все это работать! так что имейте в виду, что если вы хотите, чтобы ваше решение <strong>переопределить другие пути</strong>, вам нужно использовать sys.path.insert (0, pathname), чтобы оно заработало! для меня это было очень неприятным камнем преткновения, многие говорят, что используют функцию "добавить" в sys.path, но это не работает, если у вас уже есть определенный модуль (я нахожу это очень странным поведением)

позвольте мне поставить это здесь для моей собственной справки. я знаю, что это плохой python код, но мне нужен был скрипт для проекта, над которым я работал, и я хотел поместить скрипт в каталог scripts.import os.path import sys sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) 

как говорит @evgenisergeev в комментариях к оп, вы можете импортировать код из файла .py в произвольном месте с помощью:import imp foo = imp.load_source('module.name', '/path/to/file.py') foo.myclass() это взято из <a href="https://stackoverflow.com/a/67692/2071807">этот so ответ .

взгляните на <a href="http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports">http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . вы могли бы сделатьfrom .mod1 import stuff 

от <a href="http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports">python doc ,<blockquote> в python 2.5 вы можете переключить поведение импорта на абсолютный импорт, используя директиву from __future__ import absolute_import. такое поведение при абсолютном импорте станет будущим по умолчанию (вероятно, python 2.7). если абсолютный импорт установлен по умолчанию, import string всегда найдет версию стандартной библиотеки. рекомендуется, чтобы пользователи начали как можно больше использовать абсолютный импорт, поэтому желательно начать писать from pkg import string в вашем коде </blockquote>

вдобавок к тому, что сказал джон б., похоже, что установка переменной __package__ должна помочь, вместо изменения __main__, что может испортить другие вещи. но, насколько я мог проверить, он работает не совсем так, как должен.у меня та же проблема, и ни pep 328, ни 366 не решают ее полностью, поскольку оба, к концу дня, нуждаются в том, чтобы заголовок пакета был включен в sys.path, насколько я мог понять.я должен также упомянуть, что я не нашел, как отформатировать строку, которая должна идти в эти переменные. это "package_head.subfolder.module_name" или как?

я обнаружил, что проще установить переменную окружения "pythonpath" в верхнюю папку:bash$ export pythonpath=/path/to/app </code></pre><p>затем:</p><pre><code>import sub1.func1 #...more import </code></pre><p>конечно, pythonpath "глобальный", но это не доставило мне проблем.</p>