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

Представьте себе эту структуру каталогов:

app/ __init__.py sub1/ __init__.py mod1.py sub2/ __init__.py mod2.py 

Я mod1 , и мне нужно импортировать что-то из mod2 . Как я должен это делать?

Я пробовал from ..sub2 import mod2 но я получаю «Попытка относительного импорта в не-пакет».

Я googled вокруг, но нашел только « sys.path манипуляции» хаки. Разве нет чистого пути?


Изменить: все мои __init__.py в настоящее время пустые

Edit2: Я пытаюсь сделать это, потому что sub2 содержит классы, которые совместно используются в sub1 ( sub1 , subX и т. Д.).

Edit3: Поведение, которое я ищу, такое же, как описано в PEP 366 (спасибо John B)

  • Импорт модулей сопоставления в Python для простого рефакторинга
  • Как использовать пользовательские классы с Apache Spark (pyspark)?
  • Получение модуля nltk.wordnet Python для работы в Jython
  • Как использовать __init__.py в (под) модули для определения пространств имен?
  • Импорт модулей Python - Явный и неявный относительный импорт
  • Проблемы с настройкой модуля MySQLdb
  • ImportError: нет модуля с именем backend_tkagg
  • Свойства модуля документа Sphinx
  • 18 Solutions collect form web for “Как сделать относительный импорт в Python?”

    Кажется, все хотят сказать вам, что вы должны делать, а не просто отвечать на вопрос.

    Проблема в том, что вы используете модуль как «__main__», передав mod1.py в качестве аргумента интерпретатору.

    От PEP 328 :

    Относительный импорт использует атрибут __name__ модуля для определения позиции этого модуля в иерархии пакетов. Если имя модуля не содержит информации о пакете (например, оно установлено в «__main__»), то относительный импорт разрешается так, как если бы модуль был модулем верхнего уровня, независимо от того, где модуль фактически находится в файловой системе.

    В Python 2.6 они добавляют способность ссылаться на модули относительно основного модуля. PEP 366 описывает изменение.

    Обновление : согласно Nick Coghlan, рекомендуемая альтернатива – запустить модуль внутри пакета с помощью -m-переключателя.

     main.py setup.py app/ -> __init__.py package_a/ -> __init__.py module_a.py package_b/ -> __init__.py module_b.py 
    1. Вы запустите python main.py
    2. main.py : import app.package_a.module_a
    3. module_a.py import app.package_b.module_b

    Альтернативно, 2 или 3 могут использовать: from app.package_a import module_a

    Это будет работать до тех пор, пока у вас есть app в PYTHONPATH. main.py может быть где угодно.

    Таким образом, вы пишете setup.py чтобы скопировать (установить) весь пакет приложений и подпакеты в папки python целевой системы, а main.py – настроить папки сценариев системы.

    Вот решение, которое работает для меня:

    Я делаю относительный импорт как from ..sub2 import mod2 а затем, если я хочу запустить mod1.py тогда я mod1.py в родительский каталог app и запускаю модуль, используя ключ python -m app.sub1.mod1 качестве python -m app.sub1.mod1 .

    Настоящая причина, почему эта проблема возникает при относительном импорте, заключается в том, что относительный импорт работает, используя свойство __name__ модуля. Если модуль запускается напрямую, то __name__ устанавливается в __main__ и не содержит никакой информации о структуре пакета. И поэтому Python жалуется на relative import in non-package ошибку.

    Таким образом, используя ключ -m, вы предоставляете информацию о структуре пакета на python, с помощью которой он может успешно разрешить относительные импорт.

    Я неоднократно сталкивался с этой проблемой при относительном импорте. И, прочитав все предыдущие ответы, я все еще не мог понять, как его решить, чистым способом, без необходимости включать шаблонный код во все файлы. (Хотя некоторые из комментариев были действительно полезны, благодаря @ncoghlan и @XiongChiamiov)

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

    «Guido просматривает скрипты в пакете как анти-шаблон» (отклоненный PEP-3122 )

    Я потратил так много времени, пытаясь найти решение, прочитав связанные записи здесь о переполнении стека и сказал себе: «должен быть лучший способ!». Похоже, нет.

     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 

    Я использую этот фрагмент для импорта модулей из путей, надеюсь, что это поможет

    Это решение 100%:

    • приложение/
      • main.py
    • настройки /
      • local_setings.py

    Параметры импорта / local_setting.py в app / main.py:

    main.py:

     import sys sys.path.insert(0, "../settings") try: from local_settings import * except ImportError: print('No Import') 

    объяснение ответа nosklo's примерами

    note: все файлы __init__.py пусты.

     main.py app/ -> __init__.py package_a/ -> __init__.py fun_a.py package_b/ -> __init__.py fun_b.py 

    Приложение / package_a / fun_a.py

     def print_a(): print 'This is a function in dir package_a' 

    Приложение / package_b / fun_b.py

     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() 

    main.py

     from app.package_b import fun_b fun_b.print_b() 

    если вы запустите $ 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, и это не сработало. Что работало в sys.path.insert

     if __name__ == '__main__': sys.path.insert(0, '../..') 

    Так вроде взломать, но получил все, чтобы работать! Поэтому имейте в виду, что если вы хотите, чтобы ваше решение переопределяло другие пути, вам нужно использовать 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 в комментариях к OP, вы можете импортировать код из файла .py в произвольном месте, используя:

     import imp foo = imp.load_source('module.name', '/path/to/file.py') foo.MyClass() 

    Это взято из этого ответа SO .

    Взгляните на http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports . Вы могли бы сделать

     from .mod1 import stuff 

    Из документа Python ,

    В Python 2.5 вы можете переключить импорт на абсолютный импорт, используя директиву абсолютной_имости импорта from __future__ import absolute_import . Это абсолютное поведение импорта станет дефолтом в будущей версии (возможно, Python 2.7). Как только абсолютный импорт будет использоваться по умолчанию, import string всегда найдет версию стандартной библиотеки. Предполагается, что пользователи должны максимально использовать абсолютный импорт, поэтому лучше начать писать from pkg import string в вашем коде

    Я обнаружил, что легче установить переменную окружения «PYTHONPATH» в верхнюю папку:

     bash$ export PYTHONPATH=/PATH/TO/APP 

    тогда:

     import sub1.func1 #...more import 

    конечно, PYTHONPATH является «глобальным», но это еще не вызвало проблем для меня.

    В дополнение к тому, что сказал Джон Б., кажется, что вместо переменной __main__ следует __package__ переменную __package__ , которая может __package__ другие вещи. Но, насколько я могу проверить, он работает не так, как должен.

    У меня такая же проблема, и ни PEP 328, ни 366 не разрешают проблему полностью, так как и то, и другое к концу дня, нужно, чтобы глава пакета был включен в sys.path , насколько я мог понять.

    Следует также упомянуть, что я не нашел способ форматирования строки, которая должна входить в эти переменные. Это "package_head.subfolder.module_name" или что?

    Предположим, что вы работаете на верхнем уровне, а затем в mod1 :

     import sub2.mod2 

    вместо

     from ..sub2 import mod2 

    Зачем вам это нужно? Почему вы просто не импортируете его как

     from app.sub2 import mod2 

    Я думаю, что вы должны спросить себя:

    • Почему мне нужно это делать?
    • Является ли мое разделение пакетов хорошо выполненным?

    Я не знаю контекста, почему вы хотите сделать это таким образом. Но для меня более чистый дизайн будет иметь следующую структуру пакетов:

     app/ __init__.py sub1/ __init__.py mod1.py sub12/ __init__.py mod2.py 

    Тогда вам нужно только сделать:

     from sub12 import mod2 

    Не делайте относительного импорта. Они сделают ваш код более хрупким. Если вы сделаете абсолютный импорт, как предположил Матей, вы будете менее уязвимы к изменениям в sys.path и изменениям в расположении файлов.

    Python - лучший язык программирования в мире.