импорт локальной функции из модуля, размещенного в другом каталоге с относительным импортом в Jupyter notebook с помощью python3


у меня есть структура каталогов, аналогичная следующей

meta_project
    project1
        __init__.py
        lib
            module.py
            __init__.py
    notebook_folder
        notebook.jpynb

при работе в notebook.jpynb Если я попытаюсь использовать относительный импорт для доступа к функции function() на module.py С:

from ..project1.lib.module import function

я получаю следующую ошибку

SystemError                               Traceback (most recent call last)
<ipython-input-7-6393744d93ab> in <module>()
----> 1 from ..project1.lib.module import function

SystemError: Parent module '' not loaded, cannot perform relative import

есть ли способ заставить это работать, используя относительный импорт?

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

Обратите также внимание, что по крайней мере, как первоначально предполагалось project1 не считался модулем и поэтому не имеет __init__.py file, он просто подразумевался как каталог файловой системы. Если для решения проблемы требуется рассматривать ее как модуль и включать __init__.py файл (даже пустой) это нормально, но этого недостаточно, чтобы решить проблему.

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


Edit: это не похоже на относительный импорт в Python 3, что говорит об относительно импорта в Python 3 в целом и – в частности – запуск скрипта из каталога пакета. Это связано с работой в ноутбуке jupyter, пытающемся вызвать функцию в локальном модуле в другом каталоге который имеет как различные общие, так и частные аспекты.

3   51   2015-12-27 10:14:20

3 ответа:

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

мое решение состояло в том, чтобы сообщить Python об этом дополнительном пути импорта модуля, добавив такой фрагмент в ноутбук:

import os
import sys
module_path = os.path.abspath(os.path.join('..'))
if module_path not in sys.path:
    sys.path.append(module_path)

Это позволяет импортировать нужную функцию из иерархии модулей:

from project1.lib.module import function
# use the function normally
function(...)

обратите внимание, что необходимо добавить пустой __init__.py файлы project1/ и lib/ папки, если у вас их еще нет.

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

иерархия проекта как такового:

├── ipynb
│   ├── 20170609-Examine_Database_Requirements.ipynb
│   └── 20170609-Initial_Database_Connection.ipynb
└── lib
    ├── __init__.py
    └── postgres.py

и 20170609-Initial_Database_Connection.ipynb:

    In [1]: cd ..

    In [2]: from lib.postgres import database_connection

это работает, потому что по умолчанию ноутбук Jupyter может анализировать . Обратите внимание, что это не использует Python Notebook magic. Он просто работает без добавления %bash.

учитывая, что 99 раз из 100 я работаю в докере, используя один из Project Jupyter Docker images, следующие изменения и идемпотентных

    In [1]: cd /home/jovyan

    In [2]: from lib.postgres import database_connection

до сих пор принятый ответ работал лучше всего для меня. Однако меня всегда беспокоило, что есть вероятный сценарий, когда я могу рефакторинг notebooks каталог в подкаталоги, требующие изменения module_path в каждом ноутбуке. Я решил добавить файл python в каждый каталог ноутбука, чтобы импортировать необходимые модули.

таким образом, имея следующую структуру проекта:

project
|__notebooks
   |__explore
      |__ notebook1.ipynb
      |__ notebook2.ipynb
      |__ project_path.py
   |__ explain
       |__notebook1.ipynb
       |__project_path.py
|__lib
   |__ __init__.py
   |__ module.py

я добавил файл project_path.py в каждом подкаталоге ноутбука (notebooks/explore и notebooks/explain). Этот файл содержит код для относительного импорта (из @metakermit):

import sys
import os

module_path = os.path.abspath(os.path.join(os.pardir, os.pardir))
if module_path not in sys.path:
    sys.path.append(module_path)

таким образом, мне просто нужно сделать относительно импорта в project_path.py файл, а не в блокнотах. Файлы ноутбуков тогда просто нужно будет импортировать project_path перед импортом lib. Например, в 0.0-notebook.ipynb:

import project_path
import lib

предостережение здесь заключается в том, что реверсирование импорта не будет работать. ЭТО НЕ РАБОТАЕТ:

import lib
import project_path

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