Как выполнить относительный импорт в Python - PullRequest
23 голосов
/ 11 января 2011
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

, но получил ту же ошибку.

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

Редактировать: В Python 2

Ответы [ 6 ]

28 голосов
/ 11 января 2011

Немного поигравшись с этим, я понял, как его настроить, и ради конкретности не буду использовать имена foo bar. Каталог моего проекта настроен как ...

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) в этом пакете, все было в порядке.

11 голосов
/ 11 января 2011

хотя до тех пор, пока «вещи» нет в вашем PATH PATH, у вас нет выбора, кроме как добавить путь.

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

import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
7 голосов
/ 15 мая 2015

Я использую Python 3.4.2 в Windows 7 и оторвал себе волосы.

При запуске любого из них:

python -m unittest Python -m Unittest Discover

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

Для меня решением было опустить ".." в моем [test_stock.py]. Линия была: из ..сток импортного запаса

Изменил это на: со склада ввоз сток

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

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

C:\
  |
  +-- stock_alerter
             |
             +-- __init__.py
             +-- stock.py
             |
             \-- tests
                   |
                   +-- __init__.py
                   \-- test_stock.py
1 голос
/ 11 января 2011

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

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

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

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

.
1 голос
/ 11 января 2011

import ..foo..stuff.mylib должно быть в порядке

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

0 голосов
/ 05 февраля 2019

Если вы работаете в Linux или, возможно, * nix, вы можете взломать это с помощью символических ссылок.

stuff/
    mylib.py
    foo.py // equivalent of main.py in above
    foo/
        script.py
        mylib.py  ->  ../mylib.py
    foo2/
        script2.py
        mylib.py  ->  ../mylib.py

Вероятно, это не очень хороший пример для подражания.

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

Реализация новых исполняемых тестов не должна требовать от автора тестов глубокого понимания импорта python.

tests/
    common/
        commonlib.py
    test1/
        executable1.py
        executable2.py
        commonlib.py -> ../common/commonlib.py
    test2/
        executable1.py
        executable2.py
        commonlib.py -> ../common/commonlib.py


...