1. ホーム
  2. Python

Pythonの非パッケージ問題で相対インポートを試みる

2022-02-20 16:38:26
<パス

最近、パートナーのデバッグを手伝っているときに、パッケージの中から直接 .py ファイルを実行すると、次のようなエラーが報告されることに気づきました。 ValueError: Attempted relative import in non-package .

これは、この.pyファイルを実行したときに、パッケージフォルダ内にあり、.pyフォルダに以下のようなものがあれば、それが原因だと判明しました。

from .インポート
from .インポート

相対的なimport文の場合、エラーが報告されます。

なぜなら

相対インポートでは、パッケージ階層におけるそのモジュールの位置を決定するために、モジュールのname属性を使用します。

つまり、pythonは各モジュールの __name__ を実装する。
例えば、フォルダ構造として

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

そこで、moduleX モジュールをインポートするスクリプトを(このパッケージフォルダ外で、パッケージと同じ階層に作成した run.py などで)実行すると、moduleX の __name__ .package.subpackage1.moduleX moduleXは前の名前を取得するので moduleX.py は、相対 import 文を内部に持つことができます。

from ... import moduleA

また、moduleXが .package.subpackage1.moduleX __name__ 属性がある場合に限ります。 package がpythonインタプリタにパッケージとして認識されていること(例えば、パッケージの兄弟フォルダにあるrun.pyの実行が import package.subpackage1.moduleX といった感じです)。しかし、私が直接実行するすべての python スクリプトがトップレベルスクリプトとして扱われる場合、トップレベルスクリプトの __name__ は自動的に __main__ . そのため、もし私が moduleA.py スクリプトを実行すると、その __name__ が設定されます。 __main__ で、pythonはそれをパッケージとして扱わないので、相対import文は機能しません。

相対インポートは、現在のモジュールの名前に基づいていることに注意してください。メインモジュールの名前は常に "__main__" であるため、Python アプリケーションのメインモジュールとして使用することを意図したモジュールは、常に絶対 import を使用する必要があります。

参考にしてください。
https://docs.python.org/3/tutorial/modules.html#intra-package-references
https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time#answer-14132912