web-dev-qa-db-ja.com

ValueError:トップレベルのパッケージを超えて相対インポートを試みました

私はそれがどのように機能するかをよりよく理解するためにPythonのインポートシステムをプレイしていて、別の問題に遭遇しました。私は次の構造を持っています

pkg/
    __init__.py
    c.py
    d.py

    subpkg/
        __init__.py
        a.py
        b.py

内部a.pyには次のコードがあります。

from . import b
from .. import d

そしてc.pyの中には次のものがあります:

import subpkg.a

今、私は次のエラーを受け取ります:

ValueError:トップレベルのパッケージを超えて相対インポートを試みました

しかしなぜ?どうすれば解決できますか? IDLEからc.pyを実行していますが、pkgには__init__.pyファイルがあるため、パッケージと見なす必要があります。

最初のインポートは正常に機能しますが、機能しないのは次のとおりです。

from .. import d

なんらかの理由で親パッケージから何かをインポートしようとしているのですが、どうやらできません。

37
nbro

これは私の狂気に疑問を投げかけました。

この問題は、人々が相対インポートをパス相対ではないとして誤って取るという混乱から生じています。

相対インポートは、実行されるファイルの場所によって異なります。

この answer は、pythonモジュールが実際にどのように機能するかを詳しく説明していますが、要約します。

  1. ファイルがロードされると、名前が付けられます:
    • トップレベルスクリプトとしてロードされた場合(直接実行)、その名前は__main__です。
    • モジュールとしてロードされた場合(with import)、その名前はファイル名であり、その一部であるパッケージ/サブパッケージの名前の前にドットで区切られます- pkg.subpkg.a
  2. from ..を実行する場合、ファイル名には少なくとも2つのドットが必要です。 from ...-3ドット。

今面白い部分が来ます。

c.pyを直接実行すると、__main__という名前が付けられ、a.pyにはsubpkg.aが付きます。

2番目のステートメントのように、subpkg.aを内部で実行するには、from ..の名前に少なくとも2つのドットが必要です。

修正

pkgの外に新しいファイルを作成します。たとえば、main.py

pkg/
    __init__.py
    c.py
    d.py

    subpkg/
        __init__.py
        a.py
        b.py
main.py

Main.py内

import pkg.c

main.pyを実行すると、名前は__main__になり、a.pypkg.subpkg.aになります。 2番目のステートメントに従って、名前に2つのドットが含まれるようになり、from ..を実行できます

もう一つ。 c.pyがモジュールとしてロードされたので、fromを使用してaをロードする必要があります.py

from .subpkg import a
4
typhon04

Python 3はインポートシステムを変更したので、作業中のモジュールの周りにあるモジュールが必要になるたびに、相対的なインポートが必要になります(PYTHONPATHまたはsys.path)。

ここでの正しい使い方は

from .subpkg import a

IDLEを使用している場合、環境はまったく異なります。したがって、現在の場所をパスに追加して、インポートが再び機能するようにすることができます。

試してください:

sys.path.insert(0, '')

奇妙かもしれませんが、それはより良いもののためです

PS:この最後の方法が機能しない場合-私は現在IDLE環境を持っていません-おそらく作業ディレクトリが正しく設定されていないためです。

代わりにこの回答を試してください: https://stackoverflow.com/a/17361545/754991

2
JBernardo

私はこの解決策を見つけました:

#! /usr/bin/env python
import os
import sys
sys.path.append(os.path.realpath('.'))
from d import *
1
Alex44