2011-01-11 5 views
22
stuff/ 
    __init__.py 
    mylib.py 
    Foo/ 
     __init__.py 
     main.py 
     foo/ 
      __init__.py 
      script.py 

script.py хочет импортировать mylib.pyКак добиться относительного импорта в питона

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

Attempted relative import beyond toplevel package

Я где-то читал, что сценарий, откуда запускается программа не должна в пакете, и я попытался модифицировать структуру, которая, как так ...

stuff/ 
    mylib.py 
    foo.py // equivalent of main.py in above 
    foo/ 
     __init__.py 
     script.py 

но получил такую ​​же ошибку.

Как это сделать? Это даже адекватный подход?

Edit: В Python 2

ответ

28

После возился с ним немного больше, я понял, как это сделать, и ради конкретности я не буду использовать Foo имена баров. Мой каталог Проект создан как ...

tools/ 
    core/ 
     object_editor/ 
      # files that need to use ntlib.py 
      editor.py # see example at bottom 
      __init__.py 
     state_editor/ 
      # files that need to use ntlib.py 
      __init__.py 
     ntlib.py 
     __init__.py # core is the top level package 
    LICENSE 
    state_editor.py # equivalent to main.py for the state editor 
    object_editor.py # equivalent to main.py for the object editor 

Строка в object_editor.py выглядит как ...

from core.object_editor import editor 

Строка в editor.py выглядит как ...

from .. import ntlib 

или альтернативно

from core import ntlib 

Ключ в том, что в примере, который я дал в вопросе, «основной» скрипт запускался изнутри пакета. Как только я переместил его, создал конкретный пакет (core) и переместил библиотеку, в которой я хотел, чтобы редакторы делили (ntlib) в этот пакет, все было ханк-дори.

+1

У вас это есть. Что происходит, так это то, что вы не можете использовать относительный импорт из сценария, который вы используете из командной строки, поэтому он должен находиться на верхнем уровне организации, ссылаясь на вещи, расположенные ниже. –

+0

Почему «главный» сценарий запускался из пакета, вызывают проблемы? – Bin

1

import ..foo..stuff.mylib должно быть нормально

EDIT снял расширение

+4

Я не думаю, что это справедливо синтаксис. – random

+0

'from ..foo..stuff.mylib import any' должно быть нормально – tekknolagi

+0

import sys sys.path.append() import Bar
tekknolagi

10

, хотя до тех пор, "материал" не в вашем питона PATH у тебя нет выбора, кроме добавления пути ,

Если вы знаете, уровень вашего script.py из материала, который Вы можете сделать, например:

import sys 
import os 
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) 
+9

Является ли это документированным где-то? Не то, чтобы я вам не верю, но в случае простого желания сказать «эй, импортировать из 2 каталогов вверх», необходимо изменить системный путь, я должен увидеть это своими глазами. – random

+0

Это то, что я обычно делаю, если только из злобы. – jdm

+0

Я бы не сказал, что он точно документирован так. хотя я использовал это несколько раз сам. Он просто изменит системный путь для вашего скрипта python, а не глобально в системе. Я думаю, вы не должны возражать. : P –

1

Из PEP он кажется, что вы не можете использовать относительный импорт, чтобы импортировать файл, не упакованные.

Так что вам нужно будет добавить __init__.py запихнуть и изменить свой импорт на что-то вроде from .mylib import *

Однако PEP, кажется, не имеют никакого резерва держать MyLib упакованного в модуле. Поэтому вам может потребоваться изменить способ вызова функций библиотеки.

Другой альтернативой является переход MyLib в подпакет и импортировать его как from .libpackage import mylib

7

Я запускаю Python 3.4.2 на Windows 7 и разорвал свои волосы на этом.

При выполнении любой из них:

питон -m UnitTest питон -m UnitTest открыть

... Я бы получить 'Попытка относительно импорта за пределы верхнего уровня пакета' ошибки.

Для меня решение выбрало «..» в моей [test_stock.py]. Линия была: от ..stock импорта Stock

изменил его: складе импорта складе

.. и это работает.

структура папок:

C:\ 
    | 
    +-- stock_alerter 
      | 
      +-- __init__.py 
      +-- stock.py 
      | 
      \-- tests 
        | 
        +-- __init__.py 
        \-- test_stock.py 
+0

Ваше решение работает, но я не могу понять, почему ... Плюс, Pycharm сходит с ума от этого и красно-подчеркивает утверждение –

+0

Это работает, потому что это уже не относительный импорт, когда вы удаляете '..'. Вместо этого это абсолютный импорт. PyCharm будет использовать исходный каталог проекта для его устранения, а это означает, что вам может потребоваться вручную добавить каталог в параметры проекта, чтобы помочь им разрешить импорт. – meowsqueak

Смежные вопросы