誰かがPythonの相対的なインポートを説明できますか?


174

私の人生の中で、Pythonの相対的なインポートを機能させることはできません。それが機能しない簡単な例を作成しました:

ディレクトリ構造は次のとおりです。

/__init__.py
/start.py
/parent.py
/sub/__init__.py
/sub/relative.py

/start.py 含まれているもの: import sub.relative

/sub/relative.py ちょうど含む from .. import parent

他のすべてのファイルは空白です。

コマンドラインで次を実行すると:

$ cd /
$ python start.py

私は得ます:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: Attempted relative import beyond toplevel package

Python 2.6を使用しています。これはなぜですか?このサンドボックスの例を機能させるにはどうすればよいですか?

回答:


140

パッケージ「sub」からインポートしています。プレゼントstart.pyがあってもそれ自体は同梱されていません__init__.py

あなたは1つのディレクトリからプログラムを起動する必要がありますparent.py

./start.py

./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py

start.py

import pkg.sub.relative

これで、pkgが最上位パッケージになり、相対インポートが機能するようになります。


現在のレイアウトを使いたい場合は、そのまま使用できますimport parent。を使用start.pyしてインタープリターを起動するため、start.pyが配置されているディレクトリはPythonパスにあります。parent.py別のモジュールとしてそこに住んでいます。

__init__.pyディレクトリツリーのさらに上のスクリプトに何もインポートしない場合は、トップレベルを安全に削除することもできます。


2
「モジュール」と「パッケージ」という用語を混同している。「start.py」はモジュールを表し、「start」、「mod」、「mod.sub」はパッケージ、「mod」はトップレベルのパッケージです。
Ferdinand Beyer

34
ありがとう、しかしこれは正直に言って本当にばかげているようです。そのような美しい言語のために、デザイナーがそのような制限を設けるとは信じられません。他に方法はありませんか?
カール、

2
それはまったく愚かではありません。相対インポートは、パッケージ内の兄弟モジュールを参照するための手段です。トップレベルモジュールをインポートする場合は、絶対インポートを使用します。
Ferdinand Beyer、

58
ばかじゃない?したがって、bashでは、相対的な上位ディレクトリを ".."でアドレス指定することができなかったのではないでしょうか。
e-satis

2
Pythonのアイデアは、親スクリプトを起動したディレクトリからの「絶対」インポートを使用することです。したがって、絶対パス「import parent」を使用して、兄弟から親モジュールをインポートできます。そして、相対的な輸入レガシーまたは任意のいくつかの種類...
オデュッセウス

35

relative.py直接呼び出す場合、つまり最上位モジュールから本当にインポートしたい場合は、明示的にsys.pathリストに追加する必要があります。
これがどのように機能するかを次に示します。

# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')

# Now you can do imports from one directory top cause it is in the sys.path
import parent

# And even like this:
from parent import Parent

上記が何らかの不整合を引き起こす可能性があると思われる場合は、代わりにこれを使用できます。

sys.path.append(sys.path[0] + "/..")

sys.path[0] エントリポイントが実行されたパスを参照します。


3

python3でチェックアウトする:

python -V
Python 3.6.5

例1:

.
├── parent.py
├── start.py
└── sub
    └── relative.py

- start.py
import sub.relative

- parent.py
print('Hello from parent.py')

- sub/relative.py
from .. import parent

このように実行すると(PYTHONPATHが空であることを確認するためだけに):

PYTHONPATH='' python3 start.py

出力:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

でインポートを変更した場合 sub/relative.py

- sub/relative.py
import parent

次のように実行すると、

PYTHONPATH='' python3 start.py

出力:

Hello from parent.py

例2:

.
├── parent.py
└── sub
    ├── relative.py
    └── start.py

- parent.py
print('Hello from parent.py')

- sub/relative.py
print('Hello from relative.py')

- sub/start.py
import relative
from .. import parent

次のように実行します。

PYTHONPATH='' python3 sub/start.py

出力:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 2, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

でインポートを変更した場合sub/start.py

- sub/start.py
import relative
import parent

次のように実行します。

PYTHONPATH='' python3 sub/start.py

出力:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 3, in <module>
    import parent
ModuleNotFoundError: No module named 'parent'

次のように実行します。

PYTHONPATH='.' python3 sub/start.py

出力:

Hello from relative.py
Hello from parent.py

また、ルートフォルダからのインポートを使用することをお勧めします、すなわち:

- sub/start.py
import sub.relative
import parent

次のように実行します。

PYTHONPATH='.' python3 sub/start.py

出力:

Hello from relative.py
Hello from parent.py
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.