Как работают импорт в IPython

Я немного смущен тем, как работают операции импорта в IPython. Я ничего не обнаружил через поисковые запросы в Интернете.

Имплицитный относительный импорт работает с Python 2, но я не знаю, если это все еще имеет место с IPython для Python 3.

Относительный импорт с использованием синтаксиса точек не работает вообще:

In [6]: ls 
dsp/  __init__.py  __init__.pyc  utils/

In [7]: from .utils import capture
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-e7d50007bdd1> in <module>()
----> 1 from .utils import capture

ValueError: Attempted relative import in non-package

Импорт модулей, использующих синтаксис точек, кажется невозможным:

In [8]: cd utils
/home/user/workspace/mypkg/mypkg/utils

In [9]: ls
capture/  capture.py  capture.pyc  cext/  __init__.py  __init__.pyc

In [10]: from capture import Capture
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-10-8c31c76d052d> in <module>()
----> 1 from capture import Capture

/home/user/workspace/mypkg/mypkg/utils/capture.py in <module>()
     17 import tarfile
     18 import re
---> 19 from .. import utils
     20 from . import flprint
     21 from select import poll

ValueError: Attempted relative import in non-package

Есть ли какая-нибудь краткая документация по этому поводу?

Ответ 1

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

from capture import Capture

тогда захват становится верхним уровнем иерархии. Таким образом, оператор import в модуле захвата

from .. import utils

выходит за верхний уровень. Python не знает, что означает "..", потому что модули не осознают, к какому пакету они принадлежат. Если я вернусь к директории mypkg, я получаю ту же проблему

In [13]: cd ..
/home/user/workspace/myproj/mypkg

In [14]: from utils import capture
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-c87f26b2171d> in <module>()
----> 1 from utils import capture

/home/user/workspace/myproj/mypkg/utils/capture.py in <module>()
    18 import re
    19 import zmq
---> 20 from .. import utils
    21 from . import flprint
    22 from select import poll

ValueError: Attempted relative import beyond toplevel package

В этом случае utils - это верхний уровень, поэтому

from . import flprint

будет работать, но

from .. import utils

не будет работать.

Мне нужно переместить еще один каталог вверх:

In [19]: cd ..
/home/user/workspace/myproj

In [20]: from mypkg.utils import capture

In [21]: cap = capture.Capture

IPython может импортировать пакеты и модули, расположенные в текущем рабочем каталоге, или из каталогов в пути импорта. Я могу добавить пакет к пути импорта, чтобы иметь возможность импортировать из любого рабочего каталога.

In [23]: import sys

In [24]: sys.path.append('/home/user/workspace/myproj')

In [25]: cd
/home/user

In [26]: from mypkg.utils import capture

Вы можете использовать sys.path.append, чтобы сделать ваш модуль "самосознанием", но, как указано alpha_989, он может потенциально привести к конфликтам имен. Тем не менее, это полезное обходное решение при выполнении работы внутри иерархии пакетов с интерактивного сеанса терминала.