Вопрос

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

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

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

Я пытался from ..sub2 import mod2 но я получаю сообщение "Попытка относительного импорта без пакета".

Я погуглил , но нашел только "sys.path манипулирование" взломами.Разве нет чистого способа?


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

Редактировать 2:Я пытаюсь сделать это, потому что sub2 содержит классы, которые являются общими для всех подпакетов (sub1, subX, и т.д.).

Редактировать 3:Поведение, которое я ищу, такое же, как описано в БОДРОСТЬ ДУХА 366 (спасибо, Джон Би)

Это было полезно?

Решение

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

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

От БОДРОСТЬ ДУХА 328:

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

В Python 2.6 они добавляют возможность ссылаться на модули относительно основного модуля. БОДРОСТЬ ДУХА 366 описывает изменение.

Обновить:По словам Ника Коглана, рекомендуемой альтернативой является запуск модуля внутри пакета с помощью переключателя -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 затем я перехожу в родительский каталог app и запустите модуль, используя переключатель python -m как python -m app.sub1.mod1.

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

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

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

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

"Guido рассматривает запущенные скрипты внутри пакета как антишаблон" (отклонено ПЭП-3122)

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

Это решаемо на 100%:

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

Импорт settings/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')
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

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

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

примечание:ВСЕ __init__.py файлы пусты.

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

app/package_a/fun_a.py

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

app/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, но это не сработало.То, что действительно сработало, было системный путь.вставить

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

Так что это своего рода халтура, но все это заработало!Так что имейте в виду, если вы хотите, чтобы ваше решение переопределение других путей затем вам нужно использовать sys.path.insert(0, имя_патья), чтобы заставить его работать!Это было очень неприятным камнем преткновения для меня, многие люди говорят использовать функцию "добавить" к 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()

Это взято из это ТАКОЙ ответ.

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

from .mod1 import stuff

От Python док,

В Python 2.5 вы можете переключить поведение import на абсолютный импорт, используя 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 является "глобальным", но у меня это пока не вызвало проблем.

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

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

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

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

import sub2.mod2 

вместо того, чтобы

from ..sub2 import mod2
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top