私は次のようなディレクトリ構造を持っています
meta_project
project1
__init__.py
lib
module.py
__init__.py
notebook_folder
notebook.jpynb
notebook.jpynb
で作業しているときに、相対インポートを使用してmodule.py
の関数function()
にアクセスしようとすると:
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
相対インポートを使用してこれを機能させる方法はありますか?
ノートブックサーバーはmeta_project
ディレクトリのレベルでインスタンス化されるため、これらのファイルの情報にアクセスできる必要があります。
また、少なくとも当初意図されていたproject1
はモジュールとは考えられていなかったため、__init__.py
ファイルを持たず、単なるファイルシステムディレクトリとして使用されていました。問題の解決にモジュールとして扱い、__init__.py
ファイル(空白のファイルも含む)を含める必要がある場合は問題ありませんが、そうするだけでは問題を解決するのに十分ではありません。
私はこのディレクトリをマシン間で共有し、相対的なインポートはどこでも同じコードを使用できるようにします。また、ノートブックを使用して迅速なプロトタイピングを行うことが多いため、絶対パスを一緒にハッキングすることを含む提案は役に立たないでしょう。
編集:これは Python 3の相対インポート とは異なり、一般的にPython 3の相対インポートについて、特に内部からスクリプトを実行するパッケージディレクトリ。これは、一般的な側面と特定の側面が異なる別のディレクトリにあるローカルモジュールの関数を呼び出そうとするjupyterノートブック内での作業に関係しています。
このノートブック であなたとほとんど同じ例がありましたが、ここではDRYの方法で隣接モジュールの関数の使用法を説明したかったのです。
私の解決策は、このようなスニペットをノートブックに追加することにより、その追加モジュールインポートパスを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 Notebookがcd
コマンドを解析できるためです。これはPython Notebookマジックを使用しないことに注意してください。 %bash
を付加することなく動作します。
Project Jupyter Docker images のいずれかを使用してDockerで作業している100回のうち99回を考慮すると、次の変更isべき等
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
ファイル内で相対的なインポートを行うだけです。ノートブックファイルは、lib
をインポートする前に、project_path
をインポートするだけで済みます。たとえば、0.0-notebook.ipynb
の場合:
import project_path
import lib
ここでの注意点は、インポートの取り消しが機能しないことです。これは動作しません:
import lib
import project_path
したがって、インポート時には注意が必要です。